1、线程的五种状态
1)、新建
当new创建一个线程,例如new thread(r),线程还没开始运行,处于新建状态;
2)、就绪
新建的新线程并不会自动运行,要执行需要调用start()方法创建线程运行的系统资源,返回后,此时线程就处于就绪状态;
但是处于就绪状态的线程也并不是就能立即执行run()方法。因为线程必须同其他线程竞争CPU时间,获得CPU时间才能运行线程;(线程数>CPU数)
3)、运行
当线程获得CPU时间,进入运行状态,执行run()方法;
4)、阻塞
线程运行过程中,可能由于很多原因进入阻塞状态:
1)、线程通过调用sleep方法进入睡眠状态;
2)、线程试图获得一个锁,但是该锁被其他线程持有;
3)、线程在等待某个处罚条件;(例如定时启动线程)
所谓阻塞就是正在运行的线程没有结束,暂时让出CPU,其他处于就绪的线程就获得CPU时 间,进入运行状态。
5)、死亡
两个原因导致线程死亡:
1)、run()方法正常退出而自然死亡;
2)、一个未捕获的异常终止了run方法而使线程猝死;
用isAlive返回true,则线程可运行或被阻塞。返回false,则线程死亡或者new状态且不是可运行的。
2、volitile的理解
当两个线程共享一个数据时,则会有一个共享内存,每个线程又会有一个工作内存。这样的目的是让线程在运行时候从工作内存中拿取数据,加快运行速度,类似一个高速的本地缓存。但是会发生一个问题,就是线程1对共享内存的数据做了改变,线程2还是从工作内存拿数据,导致数据出错。(这个是并发读写常见的出错)。
所以此时就需要volatile,给变量加上valatile字段,就可以解决这个问题。
原理:在加了volatile修饰变量后,如果线程1修改了变量的值,就会在修改工作内存数据后,强制将该数据刷新到共享内存中。如果此时线程2有这个变量的副本,就会强制让线程2的变成缓存失效,不让线程2再次读取和使用。 线程2再次请求数据时,就会去共享内存拿,并且缓存到工作内存中。只是有个缺点,volatile是不能保证原子性的(涉及到复杂的指令重排、内存屏障等概念)。
参考:石杉的架构笔记等公众号。