线程
一、五种状态
1.新建(NEW):线程对象被创建后的状态
2.就绪(Runnable):当调用线程对象的start()方法,线程进入就绪状态
处于就绪状态的线程做好了被调用的准备
3.运行状态(Running):CPU开始调度处于就绪状态的线程时,此时线程真正执行
注意:就绪状态是进入到运行状态的唯一入口。即线程要进入运行状态,首先必须处于就绪状态
4.阻塞状态(Blocked):处于运行中的线程暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入运行状态才有机会再次被CPU调用进入运行状态。根据阻塞的原因,可以分为三类:
等待阻塞:运行中的线程执行wait()方法;
同步阻塞:线程获取synchronize同步锁失败(被其它线程占用);
其它阻塞:调用线程的sleep()或join()或发出了I/O请求时进入阻塞,sleep或join超时、I/O处理完毕后重新进入就绪状态
5.死亡状态(Dead):线程执行完毕或异常退出了run()方法,该线程结束生命周期
二.线程状态转换
1.调用join()、sleep()方法;sleep()时间结束或被打断;join()中断;IO完成:均会将线程改为就绪(Runnable)状态,等待调度
2.调用wait():使该线程处于等待池,直到notify()/notifyAll(),线程被唤醒放入锁定池,释放同步锁使线程回到可运行状态
3.对Runing状态的线程加同步锁,使其进入同步阻塞。锁被释放进入可运行状态
三.实现方式
1.继承Thread类,重写run方法;
2.实现Runnable接口,重写run方法;
3.通过Callbale和FutureTask创建线程;
4.通过线程池创建线程:
4.1.ExecutorServicee = Executors.newCachedThreadPool();//可变大小线程池,按照任务数分配线程
4.2.ExecutorServicee = Executors.newFixedThreadPool(3);//固定大小线程池
4.3.ExecutorServicee = Executors.newSingleThreadPool(1);//单线程池,相当于固定为1的线程池
四.线程中的异常处理
由于新线程由JVM进行调度执行,如果发生了异常,也不会通知到父线程。
(参考博客:https://www.cnblogs.com/yangfanexp/p/7594557.html 这里只提概要,不重复造轮子了)
1.解决方法1:子线程(run方法)中try..catch..
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class ChildThread implements Runnable { public void run() { doSomething1(); try { exceptionMethod();// 可能发生异常的方法 } catch (Exception e) { // 处理异常 System.out.println(String.format("handle exception in child thread. %s", e)); } doSomething2(); } }
2.解决方法2:为线程设置“未捕获异常处理器”
3.解决方法3:通过Future的get方法捕获(推荐)
在submit之后可以获得一个线程执行结果的Futrue对象,如果子线程发生了异常,通过Future.get()获取返回值时,可以捕获到异常
子线程代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class ChildThread implements Callable<String> { public String call() throws Exception { System.out.println("do something 1"); exceptionMethod(); System.out.println("do something 2"); return "test result"; } private void exceptionMethod() { throw new RuntimeException("ChildThread1 exception"); } }
父线程代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class Main { public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(8); Future future = executorService.submit(new ChildThread()); try { future.get(); } catch (InterruptedException e) { System.out.println(String.format("handle exception in child thread. %s", e)); } catch (ExecutionException e) { System.out.println(String.format("handle exception in child thread. %s", e)); } finally { if (executorService != null) { executorService.shutdown(); } } } }