线程中wait(),join(),yield() 和sleep()这个四个方法区别
1.sleep()
使当前线程(即调用该方法的线程)暂停执行一段时间,让其他线程有机会继续执行,但它并不释放对象锁。一个线程优先级为MAX_PRIORITY,另一个为MIN_PRIORITY,如果没有Sleep()方法,只有高优先级的线程执行完成后,低优先级的线程才能执行;但当高优先级的线程sleep(5000)后,低优先级就有机会执行了。
2.join()
join()方法使调用该方法的线程在此之前执行完毕,也就是等待调用该方法的线程执行完毕后再往下继续执行。注意该方法也要捕获异常。
3.yield()
它与sleep()类似,只是不能由用户指定暂停多长时间,并且yield()方法只能让同优先级的线程有执行的机会。
4.wait()和notify()notifyAll()
wait()方法使当前线程暂停执行并释放对象锁标志,让其他线程可以进入Synchronized数据块,当前线程被放入对象等待池中。当调用 notify()方法后,将从对象的等待池中移走一个任意的线程并放到锁标志等待池中,只有锁标志等待池中的线程能够获取锁标志;如果锁标志等待池中没有线程,则notify()不起作用。
多线程同时访问同个变量的并发问题
- Java 内存模型规定了所有的变量都存储在主内存中,每条线程有自己的工作内存。
- 线程的工作内存中保存了该线程中用到的变量的主内存副本拷贝,线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存。
- 线程访问一个变量,首先将变量从主内存拷贝到工作内存,对变量的写操作,不会马上同步到主内存。
- 不同的线程之间也无法直接访问对方工作内存中的变量,线程间变量的传递均需要自己的工作内存和主存之间进行数据同步。
线程的几种状态
初始状态(New)
新创建了一个线程对象就进入了初始状态,也就是通过上述新建线程的几个方法就能进入该状态。
可运行状态,就绪状态(RUNNABLE)
线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu 的使用权。以下几种方式会进入可运行状态:
- 调用start方法。
- 拿到对象锁
- 调用yield方法
运行状态(RUNNING)
可运行状态(runnable)的线程获得了cpu 时间片 ,执行程序代码。线程调度程序从可运行池中选择一个线程作为当前线程,就会进入运行状态。
阻塞状态(BLOCKED)
线程正在运行的时候,被暂停,通常是为了等待某个时间的发生(比如说某项资源就绪)之后再继续运行。wait,sleep,suspend等方法都可以导致线程阻塞。
死亡状态(DEAD)
线程run()、main() 方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。死亡的线程不可再次复生。