Java并发编程从入门到精通 - 第2章:认识Thread

线程实现的三种方法:
1、三种实现方式的简记:
 继承Thread类,重写run()方法;
 实现Runnable接口,重写run()方法,子类创建对象并作为Thread类的构造器参数;
 实现Callable接口,重写call()方法,子类创建对象并作为FutureTask类的构造器参数,FutureTask类创建对象并作为Thread类的构造器参数;
2、三种实现方法的比较:
 继承Thread类:因为是单继承,所以扩展性不好;
 实现Runnable接口:接口可以多重实现;并且还可以再继承一个类;扩展性好
 实现Callable接口:Runnable无法返回结果,且不能抛出返回的异常;而Callable接口可以,Callable产生结果,FutureTask可以拿到结果,也可以捕获Callable抛出的异常;
 最常用的就是第二种,实现Runnable接口;

 1 /**
 2  * 实现线程的方法1:继承Thread类
 3  */
 4 package thread01;
 5
 6 public class ThreadTest01
 7 {
 8     public static void main(String[] args)
 9     {
10         ThreadDemo01 threadDemo01 = new ThreadDemo01();
11         threadDemo01.start();
12
13         // 使用下面方法也能达到效果
14         /*Thread thread = new Thread(threadDemo01);
15         thread.start();*/
16
17         System.out.println("这是主线程:main结束");
18     }
19 }
20
21 class ThreadDemo01 extends Thread
22 {
23     @Override
24     public void run()
25     {
26         // 子类继承一个父类的时候,不是必须要重写父类的方法;但一个类实现一个接口的时候,这个类必须重写接口的方法;
27         // 默认调用父类的run()方法,为什么要默认调用,因为你重写的时候,可能只是为了调用父类的run()方法;既然自己真的要重写,去掉即可;
28         // super.run();
29
30         try
31         {
32             // 必须加 try...catch...,即只能捕获,不能抛出异常
33             Thread.sleep(1000);  // 使用sleep()方法模拟做了一些事(具体业务逻辑)
34         }
35         catch (InterruptedException e)
36         {
37             e.printStackTrace();
38         }
39
40         System.out.println("这是线程ThreadDemo01");
41     }
42 }

实现线程的方法1:继承Thread类

 1 /**
 2  * 实现线程的方法2:实现Runnable接口
 3  */
 4 package thread01;
 5
 6 public class RunnableTest01
 7 {
 8     public static void main(String[] args)
 9     {
10         ThreadDemo02 threadDemo02 = new ThreadDemo02();
11         Thread thread = new Thread(threadDemo02);
12         thread.start();
13
14         System.out.println("这是主线程:main结束");
15     }
16 }
17
18 class ThreadDemo02 implements Runnable
19 {
20     @Override
21     public void run()
22     {
23         try
24         {
25             Thread.sleep(1000);
26         }
27         catch (InterruptedException e)
28         {
29             e.printStackTrace();
30         }
31
32         System.out.println("这是线程ThreadDemo02");
33     }
34
35 }

实现线程的方法2:实现Runnable接口

 1 /**
 2  * 实现线程的方法3:实现Callable接口
 3  * Callable和Future:一个可以产生结果,一个可以拿到结果
 4  */
 5 package thread01;
 6
 7 import java.util.concurrent.Callable;
 8 import java.util.concurrent.ExecutionException;
 9 import java.util.concurrent.FutureTask;
10
11 public class CallableTest01
12 {
13     public static void main(String[] args)
14     {
15         ThreadDemo03 threadDemo03 = new ThreadDemo03();
16         FutureTask<String> futureTask = new FutureTask<String>(threadDemo03);
17         Thread thread = new Thread(futureTask);
18         thread.start();
19
20         try
21         {
22             // 这里既可以捕获也可以抛出异常
23             // 拿到Callable产生的结果
24             System.out.println("获取线程返回的结果:" + futureTask.get());
25         }
26         catch (InterruptedException | ExecutionException e)
27         {
28             e.printStackTrace();
29         }
30
31         System.out.println("这是主线程:main结束");
32     }
33
34
35
36 }
37
38 class ThreadDemo03 implements Callable<String>
39 {
40
41     @Override
42     public String call() throws Exception
43     {
44         try
45         {
46             // 这里不是必须要捕获异常,因为call方法默认抛出了异常
47             Thread.sleep(1000);
48         }
49         catch (Exception e)
50         {
51             e.printStackTrace();
52         }
53
54         // 上面futureTask不调用get()方法,call()方法也会执行(下面这句话也会执行),但肯定拿不到返回结果了
55         System.out.println("这是线程ThreadDemo03");
56
57         return "线程ThreadDemo03执行完毕返回的结果";
58     }
59
60 }

实现线程的方法3:实现Callable接口

 1 /**
 2  * Callable接口的使用:抛出异常
 3  */
 4 package thread01;
 5
 6 import java.util.concurrent.Callable;
 7 import java.util.concurrent.ExecutionException;
 8 import java.util.concurrent.FutureTask;
 9
10 public class CallableTest02
11 {
12     public static void main(String[] args)
13     {
14         ThreadDemo04 threadDemo04 = new ThreadDemo04();
15         FutureTask<String> futureTask = new FutureTask<String>(threadDemo04);
16         Thread thread = new Thread(futureTask);
17         thread.start();
18
19         try
20         {
21             // 异常的捕获和抛出都是通过get()方法体现的,如果没有调用get()方法,main方法执行的时候不会抛出异常;
22             System.out.println("获得线程返回的结果:" + futureTask.get());
23         }
24         catch (InterruptedException | ExecutionException e)
25         {
26             System.out.println("线程抛出了异常!");
27             e.printStackTrace();
28         }
29
30         // 如果没有上面的try...catch...语句块,结果只会输出下面一句话,不会出现异常
31         System.out.println("这是主线程:main结束");
32     }
33 }
34
35 class ThreadDemo04 implements Callable<String>
36 {
37     @Override
38     public String call() throws Exception
39     {
40         int sum = 1 / 0;
41         System.out.println("sum = " + sum);
42
43         return "线程ThreadDemo04执行完毕返回的结果";
44     }
45
46 }

Callable接口的使用:抛出异常

Thread里面的属性和方法:

 1 /**
 2  * Thread类里面的属性和方法
 3  */
 4 package thread01;
 5
 6 public class ThreadTest02
 7 {
 8     public static void main(String[] args)
 9     {
10         ThreadDemo05 threadDemo05 = new ThreadDemo05();
11         Thread thread = new Thread(threadDemo05);
12         thread.start();
13
14         // 返回当前正在执行的线程对象的引用
15         Thread currentThread = Thread.currentThread();
16         System.out.println("主线程的名称:" + currentThread.getName());
17         System.out.println("主线程所在的线程组中活动线程的数量:" + Thread.activeCount());
18         System.out.println("主线程的标识符:" + currentThread.getId());
19         System.out.println("主线程的优先级:" + currentThread.getPriority());
20         System.out.println("主线程的状态:" + currentThread.getState());
21         System.out.println("主线程所属的线程组:" + currentThread.getThreadGroup());
22         System.out.println("测试主线程是否处于活动状态:" + currentThread.isAlive());
23         System.out.println("测试主线程是否为守护线程:" + currentThread.isDaemon());
24     }
25 }
26
27 class ThreadDemo05 implements Runnable
28 {
29     @Override
30     public void run()
31     {
32         try
33         {
34             Thread.sleep(3000);
35         }
36         catch (InterruptedException e)
37         {
38             e.printStackTrace();
39         }
40
41         System.out.println("=================================");
42
43         // 返回当前正在执行的线程对象的引用
44         Thread currentThread = Thread.currentThread();
45         System.out.println("当前线程的名称:" + currentThread.getName());
46         System.out.println("返回当前线程所在的线程组中活动线程的数量:" + Thread.activeCount());
47         System.out.println("返回当前线程的标识符:" + currentThread.getId());
48         System.out.println("返回当前线程的优先级:" + currentThread.getPriority());
49         System.out.println("返回当前线程的状态:" + currentThread.getState());
50         System.out.println("返回当前线程所属的线程组:" + currentThread.getThreadGroup());
51         System.out.println("测试线程是否处于活动状态:" + currentThread.isAlive());
52         System.out.println("测试当前线程是否为守护线程:" + currentThread.isDaemon());
53     }
54
55 }

Thread类里面的属性和方法

线程的中断机制:
1、详述:
 Java中断机制是一种协作机制,也就是说通过中断不能直接终止另一个线程,而需要被请求中断的线程自己处理中断,且该线程可以选择接受请求中断自己,也可以选择不接受请求不中断自己;
 每个线程都有一个boolean类型的标识(中断状态位),代表是否有中断请求(该请求可以来自所有线程,包括被中断的线程本身),如果有中断请求,该标志位会被设置为true;
2、三个方法的比较:
 public void interrupt():
  用于中断线程;调用该方法仅仅只是将线程的中断状态位设为true,并不会真的停止线程,还是需要用户自己去监视线程的状态位并做处理;
  中断是通过调用Thread.interrupt()方法来做的;这个方法通过修改被调用线程的中断状态来告知那个线程,说它被请求中断了;对于非阻塞中的线程,只是改变了中断状态,即Thread.isInterrupted()将返回true;对于可取消的(不解)阻塞状态中的线程,比如等待在这些函数上的线程:Thread.sleep(),Object.wait(),Thread.join()等,这个线程收到中断信号后,会抛出InterruptedException,同时会把中断状态置回为false;
  当一个线程处于中断状态时(意思是它的中断状态位为true),如果再由wait、sleep以及jion三个方法引起的阻塞,那么JVM会将线程的中断标志重新设置为false,并抛出一个InterruptedException异常;
  本质作用:根据try-catch功能块捕捉jvm抛出的InterruptedException异常来做各种处理,比如如何退出线程;总之interrupt的作用就是需要用户自己去监视线程的状态位并做处理;
 public static boolean interrupted():返回线程的上次的中断状态,并清除中断状态(清除是什么意思,将true改为false,还是既不是true也不是false);
 public boolean isInterrupted():判断线程是否中断;

 1 /**
 2  * 线程的中断机制1
 3  */
 4 package thread01;
 5
 6 public class InterruptTest01
 7 {
 8     public static void main(String[] args) throws InterruptedException
 9     {
10         ThreadDemo06 threadDemo06 = new ThreadDemo06();
11         Thread thread = new Thread(threadDemo06);
12         System.out.println("启动线程...");
13         thread.start();
14
15         Thread.sleep(1000);
16
17         System.out.println("请求中断线程...");
18         // 这里的thread就是指子线程,但是是在主线程中执行这条语句的,所以叫主线程请求中断子线程
19         thread.interrupt();
20         System.out.println("判断被请求中断的线程是否被中断(判断中断标志位):" + thread.isInterrupted());
21
22         Thread.sleep(1000);
23
24         // 请求中断主线程(线程请求中断自己)
25         Thread.currentThread().interrupt();
26         // 判断主线程是否被请求中断
27         System.out.println("判断主线程main是都被中断(判断中断标志位):" + Thread.currentThread().isInterrupted());
28
29         System.out.println("应用程序执行完毕,退出...");
30
31     }
32 }
33
34 class ThreadDemo06 implements Runnable
35 {
36     boolean flag = false;
37
38     @Override
39     public void run()
40     {
41         while(!flag)
42         {
43             System.out.println("线程开始执行...");
44
45             long currentTime = System.currentTimeMillis();
46             while(System.currentTimeMillis() - currentTime < 5000)
47             {
48                 // 让该循环持续一段时间,让上面打印语句执行次数少一点
49             }
50
51             System.out.println("判断当前线程是否被中断(判断中断标志位):" + Thread.currentThread().isInterrupted());
52         }
53
54         System.out.println("线程在中断请求下中断退出");
55     }
56 }
57
58 /*
59 运行结果:
60 启动线程...
61 线程开始执行...
62 请求中断线程...
63 判断被请求中断的线程是否中断(判断中断标志位):true
64 应用程序执行完毕,退出...
65 线程开始执行...
66 线程开始执行...
67 线程开始执行...
68 线程开始执行...
69 线程开始执行...
70 线程开始执行...
71
72 根据结果可以看出,主线程请求中断正在执行的子线程,只是将子线程的中断标志位改变了,并没有真正中断子线程;
73 子线程根据自己的需要判断是否接受中断请求,可以接受中断,也可以接受不中断;
74 本实例中子线程并没有被中断;
75 */

线程的中断机制1

 1 /**
 2  * 线程的中断机制2
 3  */
 4 package thread01;
 5
 6 public class InterruptTest02
 7 {
 8     public static void main(String[] args) throws InterruptedException
 9     {
10         ThreadDemo07 threadDemo07 = new ThreadDemo07();
11         Thread thread = new Thread(threadDemo07);
12         System.out.println("启动线程...");
13         thread.start();
14
15         Thread.sleep(5000);
16
17         System.out.println("请求中断线程...");
18         thread.interrupt();
19
20         Thread.sleep(1000);
21         System.out.println("判断被请求中断的线程是否被中断(仅判断中断标志位):" + thread.isInterrupted());
22
23         System.out.println("应用程序退出!");
24     }
25 }
26
27 class ThreadDemo07 implements Runnable
28 {
29     private boolean flag = false;
30
31     @Override
32     public void run()
33     {
34         while(!flag)
35         {
36             System.out.println("线程开始执行...");
37
38             long currentTime = System.currentTimeMillis();
39             while(System.currentTimeMillis() - currentTime < 1000)
40             {
41
42             }
43
44             // 需要线程自己处理中断请求
45             if(Thread.currentThread().isInterrupted())
46             {
47                 break;
48             }
49         }
50
51         System.out.println("线程在中断请求下中断退出!");
52     }
53 }
54
55 /*
56 运行结果:
57 启动线程...
58 线程开始执行...
59 线程开始执行...
60 线程开始执行...
61 线程开始执行...
62 线程开始执行...
63 线程开始执行...
64 请求中断线程...
65 线程在中断请求下中断退出!
66 判断被请求中断的线程是否被中断(仅判断中断标志位):true
67 应用程序退出!
68
69 根据结果可以看出:被请求中断的线程需要自己根据需要决定是否中断退出;
70 */

线程的中断机制2

 1 /**
 2  * 线程的中断机制3
 3  */
 4 package thread01;
 5
 6 public class InterruptTest03
 7 {
 8     public static void main(String[] args) throws InterruptedException
 9     {
10         ThreadDemo08 threadDemo08 = new ThreadDemo08();
11         Thread thread = new Thread(threadDemo08);
12         System.out.println("启动线程...");
13         thread.start();
14
15         Thread.sleep(2000);
16         System.out.println("2秒后请求中断线程(线程还在休眠)...");
17         thread.interrupt();
18
19         Thread.sleep(1000);
20         System.out.println("应用程序结束退出!");
21
22     }
23 }
24
25 class ThreadDemo08 implements Runnable
26 {
27     @Override
28     public void run()
29     {
30         try
31         {
32             System.out.println("线程正在休眠5秒钟...");
33             Thread.sleep(5000);
34             // Thread.currentThread().join(5000);
35         }
36         catch (InterruptedException e)
37         {
38             System.out.println("线程休眠被打断,抛出异常...");
39         }
40     }
41 }
42 /*
43 运行结果:
44 启动线程...
45 线程正在休眠5秒钟...
46 2秒后请求中断线程(线程还在休眠)...
47 线程休眠被打断,抛出异常...
48 应用程序结束退出!
49
50 根据结果可以看出:处于睡眠中(调用sleep()方法)的线程,如果被请求中断,就会抛出中断异常(InterruptedException)
51 */

线程的中断机制3

线程的生命周期:
1、线程生命周期的5中状态:
(1)、新建(new Thread):此时线程有自己的内存空间,但并没有运行;且线程还不是活着的;
(2)、就绪(runnable):线程已经被启动(具备了运行条件),正在等待被分配给CPU时间片(不一定会被立即执行,处于线程就绪队列);此时线程是活着的;
(3)、运行(running):线程获得CPU资源正在执行任务(执行run()方法);此时除非线程放弃CPU或者有优先级更高的线程进入,线程将一直运行到结束;此时线程是活着的;
(4)、阻塞(blocked):由于某种原因导致正在运行的线程让出CPU并暂停自己的操作(任务执行),即进入阻塞状态;此时线程还是活着的;阻塞原因如下:
  正在休眠:线程调用sleep(long t)方法进入休眠,休眠到指定时间后进入就绪状态;
  正在等待:线程调用wait()方法,可调用notify()方法回到就绪状态;
  被另一个线程所阻塞:调用suspend()方法,可调用resume()方法恢复;
(5)、死亡(dead):当线程执行完毕或被其他线程杀死,线程就进入死亡状态;此时线程不可能再进入就绪状态等待执行;此时线程不是活着的;
  死亡原因如下:
   自然终止:正常运行run()方法后终止;
   异常终止:调用stop()方法让一个线程终止运行;
2、与线程状态对应的常用方法:
run():必须被重写,实现具体的业务功能;
start():启动线程;
sleep():释放CPU执行权,不释放锁;
wait():释放CPU执行权,释放锁;当一个线程执行到wait()方法时,它就进入到一个和该对象相关的等待池(Waiting Pool)中,同时失去了对象锁,只是暂时失去对象锁,wait后(不解)还要返还对象锁;当前线程必须拥有当前对象的锁,如果当前线程不是此锁的拥有者,会抛出IllegalMonitorStateException异常,所以wait()必须在同步块(synchronized block)中调用;
notify()/notifyAll():唤醒在当前对象等待池中等待的第一个线程/所有线程;notify()/notifyAll()也必须拥有相同对象锁,否则也会抛出IllegalMonitorStateException异常;
yied():使当前正在运行的线程临时暂停,让出CPU的使用权,让同等优先权的线程运行(但并不保证当前线程会被JVM再次调度,使该线程重新进入Running状态);如果没有同等优先权的线程,那么yied()方法将不会起作用;
3、状态转换:
 新建 -> 就绪:
  start();
 就绪 -> 运行:
  获得CPU执行权;
 运行 -> 就绪:
  yield();
 运行 -> 阻塞:
  sleep()、wait()、join()、synchronized;
 阻塞 -> 就绪:
  sleep()结束、wait()结束、IO完成;
 运行 -> 死亡:
  正常结束、异常退出;

守护线程:
 可以简单的理解为后台运行线程;
 进程结束,守护线程跟着自动结束,不需要手动的去关心和通知其状态;
 Java的垃圾回收是一个守护线程;
 当正在运行的线程都是守护线程时,Java虚拟机退出;
 JRE判断程序是否执行结束的标准是所有的前台运行线程执行完毕了,而不管后台线程的状态;
 当进程中所有非守护线程已结束或退出时,即使仍有守护线程在运行,进程仍将结束;

线程组:

ThreadLocal:
 当前线程副本;
 当使用 ThreadLocal 维护变量的时候,ThreadLocal 为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其他线程对应的副本;从线程的角度看,目标变量就像是线程的本地变量;
 ThreadLocal在处理线程的局部变量的时候比synchronized同步机制解决线程安全问题更简单、更方便,且结果程序拥有更高的并发性;
 注意:使用ThreadLocal,一般都是声明在静态变量(没说局部变量)中,如果不断创建ThreadLocal而且没有调用其remove()方法,将会导致内存泄漏;

 1 /**
 2  * ThreadLocal的使用
 3  */
 4 package thread01;
 5
 6 public class ThreadLocalTest01
 7 {
 8     // 通过匿名内部类覆盖ThreadLocal的initialValue()方法,指定初始值
 9     // 可以不加static
10     private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>()
11     {
12         // 默认的是protected修饰符
13         // protected Integer initialValue() {};
14         // 重写此方法,返回该线程变量的初始值
15         public Integer initialValue()
16         {
17             return 0;
18         }
19     };
20
21     // 获得当前变量
22     public ThreadLocal<Integer> getThreadLocal()
23     {
24         return seqNum;
25     }
26
27     // 实现读取下一个序列值
28     public int getNexNum()
29     {
30         seqNum.set(seqNum.get() + 1);
31         return seqNum.get();
32     }
33
34     // 定义成员内部类
35     // 这里加static只是为了能在main方法中使用
36     private static class TestClient implements Runnable
37     {
38         private ThreadLocalTest01 tl;
39
40         public TestClient(ThreadLocalTest01 tl)
41         {
42             this.tl = tl;
43         }
44
45         @Override
46         public void run()
47         {
48             for(int i=0;i<3;i++)
49             {
50                 // 每个线程打出三个序列值
51                 System.out.println("thread[" + Thread.currentThread().getName() + "] --> tl[" + tl.getNexNum() + "]");
52             }
53
54             // 每个线程用完的时候要记得删除
55             tl.getThreadLocal().remove();
56         }
57
58     }
59
60     public static void main(String[] args)
61     {
62         ThreadLocalTest01 threadLocalTest01 = new ThreadLocalTest01();
63
64         // 三个线程共享threadLocalTest01,格子产生序列号
65         TestClient testClient1 = new TestClient(threadLocalTest01);
66         TestClient testClient2 = new TestClient(threadLocalTest01);
67         TestClient testClient3 = new TestClient(threadLocalTest01);
68
69         Thread thread1 = new Thread(testClient1);
70         Thread thread2 = new Thread(testClient2);
71         Thread thread3 = new Thread(testClient3);
72
73         thread1.start();
74         thread2.start();
75         thread3.start();
76     }
77 }

ThreadLocal的使用

线程的异常处理:
 详解:
  run方法不允许抛出异常,所有的异常必须在run方法中进行处理;就是说run方法中可以抛出异常,但不能往run方法外抛出异常,在run方法里面抛出的异常也必须在run方法内处理掉;
  在run方法中,抛出的已检查异常(checked exception)必须使用try...catch...进行处理,否则报错,编译不通过;(不是在run方法中抛出已检查异常,则既可以使用try...catch...进行处理,也可以使用throws继续往上抛)
  在run方法中,虽然向外抛出未检查异常不会报错,但这样不合理(run方法中的异常应该在run处理);
 线程中处理异常的方法总结:
  不能直接在一个线程中抛出异常;
  如果是已检查异常(checked exception),推荐采用try...catch...块来处理;
  如果是未检查异常(unchecked exception),推荐方法:注册一个实现UncaughtExceptionHandler接口的对象实例来处理;
 线程中,处理未检查异常的方法的具体步骤总结:
  定义一个类实现UncaughtExceptionHandler接口,在需要实现的方法里面包含对异常处理的逻辑和步骤;
  定义一个线程,执行需要的业务逻辑功能;
  在创建和执行该子线程的方法中,在thread.start()语句前增加一个thread.setUncaughtExceptionHandler(自定义异常处理类对象)语句来实现异常处理逻辑的注册;

  1 /**
  2  * 线程中,对已检查异常的处理
  3  */
  4 package thread01;
  5
  6 import java.io.FileWriter;
  7 import java.io.IOException;
  8
  9 public class CheckedExceptionTest
 10 {
 11     public static void main(String[] args)
 12     {
 13         ThreadDemo09 threadDemo09 = new ThreadDemo09();
 14         Thread thread = new Thread(threadDemo09);
 15         thread.start();
 16     }
 17 }
 18
 19 class ThreadDemo09 implements Runnable
 20 {
 21     @Override
 22     public void run()
 23     {
 24         // 不能在try中声明,这样会导致finally中无法只用;
 25         FileWriter fw = null;
 26
 27         try
 28         {
 29             // 在线程的run()方法中,对于抛出的已检查异常,必须且只能使用try...catch...在run方法内部进行处理,不处理则直接报错(编译不过)
 30             // 抛出异常的原因:可能找不到文件路径;
 31             fw = new FileWriter("F:/ppt/text.txt");
 32         }
 33         catch (IOException e1)
 34         {
 35             e1.printStackTrace();
 36         }
 37         finally
 38         {
 39             // 无论程序怎么运行,最后都要关闭流;
 40             // 一旦路径有误,fw就会出现空指针异常,所以要先判断fw是否为空
 41             if(null != fw)
 42             {
 43                 try
 44                 {
 45                     fw.close();
 46                 }
 47                 catch (IOException e)
 48                 {
 49                     e.printStackTrace();
 50                 }
 51             }
 52         }
 53     }
 54
 55     public void testCheckedException()
 56     {
 57         // 非run方法中抛出的已检查异常,既可以使用try...catch...进行捕获,也可以继续抛出;
 58         // 以下是使用try...catch...进行捕获处理
 59
 60         // 不能在try中声明,这样会导致finally中无法只用;
 61         FileWriter fw = null;
 62
 63         try
 64         {
 65             // 对于抛出的已检查异常,必须且只能使用try...catch...在run方法内部进行处理,不处理则直接报错(编译不过)
 66             // 抛出异常的原因:可能找不到文件路径;
 67             fw = new FileWriter("F:/ppt/text.txt");
 68         }
 69         catch (IOException e1)
 70         {
 71             e1.printStackTrace();
 72         }
 73         finally
 74         {
 75             // 无论程序怎么运行,最后都要关闭流;
 76             // 一旦路径有误,fw就会出现空指针异常,所以要先判断fw是否为空
 77             if(null != fw)
 78             {
 79                 try
 80                 {
 81                     fw.close();
 82                 }
 83                 catch (IOException e)
 84                 {
 85                     e.printStackTrace();
 86                 }
 87             }
 88         }
 89     }
 90
 91     public void testCheckedException2() throws IOException
 92     {
 93         // 非run方法中抛出的已检查异常,既可以使用try...catch...进行捕获,也可以继续抛出;
 94         // 以下是使用 throws 继续往外抛
 95         FileWriter fw = new FileWriter("F:/ppt/text.txt");
 96
 97         if(null != fw)
 98         {
 99             fw.close();
100         }
101     }
102
103 }

线程中,对已检查异常的处理

 1 /**
 2  * 线程中,对未检查异常的处理
 3  */
 4 package thread01;
 5
 6 import java.lang.Thread.UncaughtExceptionHandler;
 7
 8 public class UncheckedExceptionTest
 9 {
10     public static void main(String[] args)
11     {
12         ThreadDemo10 threadDemo10 = new ThreadDemo10();
13         Thread thread = new Thread(threadDemo10);
14         thread.setUncaughtExceptionHandler(new UncheckedExcepionHandlerDemo());
15         thread.start();
16     }
17 }
18
19 class ThreadDemo10 implements Runnable
20 {
21     // 在线程的run方法中,对于未检查异常:可以不处理;可以继续往外抛;也可以使用try..catch..进行捕获处理;
22     @Override
23     public void run() // throws NumberFormatException
24     {
25         // 抛出类型转换异常
26         int result = Integer.parseInt("ijn");
27         System.out.println(result);
28     }
29
30     public void testUncheckedException1()
31     {
32         // 在非run()方法中,对于未检查异常:可以不处理;可以继续往外抛;也可以使用try..catch..进行捕获处理;
33         // 以下是不处理
34         int result = Integer.parseInt("ijn");
35         System.out.println(result);
36     }
37
38     public void testUncheckedException2()
39     {
40         // 在非run()方法中,对于未检查异常:可以不处理;可以继续往外抛;也可以使用try..catch..进行捕获处理;
41         // 以下通过try..catch..进行捕获处理
42         int result = 0;
43         try
44         {
45             result = Integer.parseInt("ijn");
46         }
47         catch (NumberFormatException e)
48         {
49             e.printStackTrace();
50         }
51         System.out.println(result);
52     }
53
54     public void testUncheckedException3() throws NumberFormatException
55     {
56         // 在非run()方法中,对于未检查异常:可以不处理;可以继续往外抛;也可以使用try..catch..进行捕获处理;
57         // 以下是使用 throws 继续往外抛
58         int result = Integer.parseInt("ijn");
59         System.out.println(result);
60     }
61 }
62
63 class UncheckedExcepionHandlerDemo implements UncaughtExceptionHandler
64 {
65     @Override
66     public void uncaughtException(Thread t, Throwable e)
67     {
68         System.out.println("一个未检查异常被捕获...");
69         System.out.println("线程id:" + t.getId());
70         System.out.println("异常名称:" + e.getClass().getName() + ",异常信息:" + e.getMessage());
71         System.out.println("异常栈信息:");
72         e.printStackTrace(System.out);
73         System.out.println("线程状态:" + t.getState());
74     }
75 }

线程中,对未检查异常的处理

原文地址:https://www.cnblogs.com/kehuaihan/p/8458278.html

时间: 2024-10-28 15:41:15

Java并发编程从入门到精通 - 第2章:认识Thread的相关文章

Java并发编程从入门到精通 - 第3章:Thread安全

Java内存模型与多线程: 线程不安全与线程安全: 线程安全问题阐述:  多条语句操作多个线程共享的资源时,一个线程只执行了部分语句,还没执行完,另一个线程又进来操作共享数据(执行语句),导致共享数据最终结果出现误差:所以就是看一个线程能否每次在没有其他线程进入的情况下操作完包含共享资源的语句块,如果能就没有安全问题,不能就有安全问题: 如何模拟多线程的安全问题:  用Thread.sleep()方法模拟: 放在哪:放在多线程操作共享数据的语句块之间(使正在运行的线程休息一会,让其他线程执行,就

Java并发编程从入门到精通 - 第6章:线程池

1.什么是线程池(为什么使用线程池):2.Executor框架介绍:  Java 5中引入的,其内部使用了线程池机制,在java.util.cocurrent 包下,通过该框架来控制线程的启动.执行和关闭(使用该框架来创建线程池),可以简化并发编程的操作:  Executor框架包括:线程池,Executor,Executors,ExecutorService,CompletionService,Future,Callable等:  ExecutorService接口继承自Executor接口,

Java并发编程从入门到精通 - 第5章:多线程之间的交互:线程阀

详述: 线程阀是一种线程与线程之间相互制约和交互的机制: 作用:http://wsmajunfeng.iteye.com/blog/1629354阻塞队列BlockingQueue:数组阻塞队列ArrayBlockingQueue:链表阻塞队列LinkedBlockingQueue:优先级阻塞队列PriorityBlockingQueue:延时队列DelayQueue:同步队列SynchronousQueue:链表双向阻塞队列LinkedBlockingDeque:链表传输队列LinkedTra

Java并发编程从入门到精通 - 第7章:Fork/Join框架

1.综述:化繁为简,分而治之:递归的分解和合并,直到任务小到可以接受的程度:2.Future任务机制:  Future接口就是对于具体的Runnable或者Callable任务的执行结果进行取消.查询是否完成.获取结果:必要时可以通过get方法获取执行结果,该方法会阻塞直到任务会返回结果:也就是说Future接口提供三种功能:判断任务是否完成.能够中断任务.能够获取任务执行结果:  Future接口里面的常用方法:3.FutureTask:  FutureTask类是Future接口唯一的实现类

Java并发编程从入门到精通 张振华.Jack --我的书

[当当.京东.天猫.亚马逊.新华书店等均有销售] 目 录 第一部分:线程并发基础 第1章 概念部分   1 1.1 CPU核心数.线程数 (主流cpu,线程数的大体情况说一下) 1 1.2 CPU时间片轮转机制 2 1.3 什么是进程和什么是线程 4 1.4 进程和线程的比较 5 1.5 什么是并行运行 7 1.6 什么是多并发运行 8 1.7 什么是吞吐量 9 1.8  多并发编程的意义及其好处和注意事项 10 1.9  分布式与并发运算关系 11 1.10 Linux和Window多并发可以

Java并发编程从入门到精通 张振华.Jack --【吐血推荐、热销书籍】

[当当.京东.天猫.亚马逊.新华书店等均有销售]目 录 第一部分:线程并发基础 第1章 概念部分   1 1.1 CPU核心数.线程数 (主流cpu,线程数的大体情况说一下) 1 1.2 CPU时间片轮转机制 2 1.3 什么是进程和什么是线程 4 1.4 进程和线程的比较 5 1.5 什么是并行运行 7 1.6 什么是多并发运行 8 1.7 什么是吞吐量 9 1.8  多并发编程的意义及其好处和注意事项 10 1.9  分布式与并发运算关系 11 1.10 Linux和Window多并发可以采

Java并发编程从入门到精通-总纲

总纲: Thread; Thread安全; 线程安全的集合类; 多线程之间交互:线程阀; 线程池; Fork/Join; 第2章:认识Thread: 线程实现的三种方法; Thread里面的属性和方法; 线程的中断机制; 线程的生命周期; 守护线程; 线程组; 当前线程的副本:ThreadLocal; 线程异常的处理; 第3章:Thread安全: Java内存模型与多线程: 线程不安全和线程安全: 隐式锁synchronized: 显式锁Lock和ReentrantLock: 显式锁ReadWr

Java网络编程从入门到精通(4):DNS缓存

在通过DNS查找域名的过程中,可能会经过多台中间DNS服务器才能找到指定的域名,因此,在DNS服务器上查找域名是非常昂贵的操作.在Java中为了缓解这个问题,提供了DNS缓存.当InetAddress类第一次使用某个域名(如www.csdn.net)创建InetAddress对象后,JVM就会将这个域名和它从DNS上获得的信息(如IP地址)都保存在DNS缓存中.当下一次InetAddress类再使用这个域名时,就直接从DNS缓存里获得所需的信息,而无需再访问DNS服务器. DNS缓存在默认时将永

[Java 并发] Java并发编程实践 思维导图 - 第六章 任务执行

根据<Java并发编程实践>一书整理的思维导图.希望能够有所帮助. 第一部分: 第二部分: 第三部分: