线程5大状态分析
上图是线程从创建到消亡的一个切换过程。下面我们简单类分析每一个状态。
- 新建状态:新建状态具体是指调用new Thread()创建出线程对象,但是还没有调用start方法的这段时间。前面的一篇文章《Java虚拟机剖析之内存区域,内存的溢出,泄漏》一文中有说到,每一个线程都会有自己的私有内存区域。处于新建状态下的线程,此时还未分配系统资源,也即是还没有分配到私有内存。
- 就绪状态:start方法刚被调用的一段时机。处于当前状态的线程已经分配到所需资源,但是还没有获得CPU使用权,在此状态的线程会相互竞争CPU使用权。
- 运行状态:被os选中,获得CPU使用权,开始执行任务,也即是开始运行run/main方法。
- 阻塞状态:在执行任务的过程中由于一些原因导致线程阻塞(后面会重点讲阻塞状态,这也是本文重点)。
- 终止状态:任务执行完毕(run/main方法执行完毕)或者线程异常终止。
阻塞状态,阻塞原因
阻塞状态对我们开发人员来说是最关键的一个状态,因为我们能通过各种造成阻塞的手段合理的调度指定的线程执行特定的任务,能准确的控制每一个任务执行的时机。造成阻塞的原因大致为下面4种:
- 调用sleep/join方法
- 调用wait方法
- 访问临界资源时(如synchronized字段修饰的方法或者代码块),等待竞争锁对象所有权
- I/O导致阻塞(比如:等待用户输入)
关键方法分析sleep,join,wait,notify,notifyAll,yield
- sleep方法是Thread的静态方法,当该方法调用时,会让调用的线程进入阻塞状态,直到历时sleep的参数时间后唤醒该线程。当线程在持有临界资源对象锁持有权时调用sleep方法,线程进入阻塞,不会释放所持有的对象锁持有权,容易造成死锁。
- join方法是Thread的公有方法,归对象所有。在A线程中调用B线程的join方,A线程进入阻塞状态,知道B线程的任务执行完毕才会唤醒A线程继续执行未完成的任务。
- wait方法是超类Object的方法,该方跟notify/notifyAll配套使用,这一对方法用于线程间通讯控制并发。这一对方法需要线程在持有临界资源对象锁所有权的情况下才能调用,否则抛出IllegalMonitorStateException。调用wait方法的线程交出CPU使用权进入阻塞状态,需等到竞争同一锁对相的线程调用notify/notifyAll方法才会被唤醒(notify是在所有相关的处于等待状态的线程中随机选择一个线程唤醒,notifyAll是将所有相关的处于等待状态的线程全部唤醒),然后进入锁池,重新竞争对象锁的持有权。wait方法调用的线程会释放临界资源对象锁的持有权。
- yield方法是Thread的静态方法,调用该方法的线程相当于线程的时间片用完,回到就绪状态,重新竞争跟同等优先级线程CPU使用权(直观的说就是A,B线程为同等优先级线程,同时开始竞争CPU使用权。A线程获取到CPU使用权进入运行状态,正在执行任务,run方法运行到一半的时候调用了yield方法,此时A线程将会跟B线程再一次平等继续竞争CPU使用权,如果A得到使用权,会继续刚才完成到一半的任务继续未完成的任务执行完)
- 另外suspend和resume方法配对使用,跟wait和notify/notifyAll这一对差不多,调用suspend的线程进入阻塞,需要等到对应的resume方法被调用才会唤醒。但是有一个区别是suspend方法调用的线程会释放对象锁的持有权。这对方法不经常用,所以略过。。。
sleep和wait方法的区别及特性验证
共同点:
- 都能是线程进入阻塞状态
- 都可以设置阻塞时间
- 唤醒方式不同,sleep方法是在指定的时间之后自动唤醒。wait必须等到别的相关线程调用notify/notifyAll才会唤醒(当然了,wait(long time)方法也能指定等待时间,等待时间到了之后还未调用notify/notifyAll将会自动唤醒,特殊情况)
- sleep调用时不一定需要线程持有临界资源的对象锁,但是wait方法的调用线程必须持有临界资源的对象锁,否则会抛出异常。
- 调用sleep方法进入阻塞状态后不会释放持有的对象锁,但是wait方法会释放所持有的对象锁(主要区别)
工厂:
package com.example; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; /** * Created by PICO-USER on 2017/11/7. */ public class FactoryClass { //用于存放产品的容器 public List<String> products = new ArrayList<>(); /** * 生产量是否已经达到饱满 * * @return true 表示已经饱满 */ private boolean isFull() { return products.size() >= 40 ? true : false; } /** * 库存是否已经为0 * * @return true 表示已售完 */ private boolean isEmpty() { return products.size() <= 0 ? true : false; } /** * 商店卖东西,调用wait进入阻塞 * * @param consumer