线程实现的三种方法:
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 /** 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 }
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 }
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 }
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 }
线程的中断机制:
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 /** 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 */
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 */
线程的生命周期:
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 }
线程的异常处理:
详解:
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 }