java Thread 学习
来源:互联网 发布:数控车床梯形螺纹编程 编辑:程序博客网 时间:2024/04/28 07:54
之前说过 Thread 的两种实现方式,一种是继承Thread类,一种是实现Runnable接口。 两种实现方式的异同如下:
其实就是Class 和 Interface 之间的不同。
Runnable 为一个接口,由于接口的多实现性,使其更具可扩展性,而且有利于资源的共享。比如,一个实现了Runnable接口的对象可以创建多个线程,使他们可以共享该对象的资源。
二、线程的五种状态包括
新建(new)
就绪(Runnable)
运行(Running)
阻塞(Blocked)
死亡(Dead)
1. 新建状态(New) : 线程对象被创建后,就进入了新建状态。例如,Thread thread = new Thread()。
2. 就绪状态(Runnable): 也被称为“可执行状态”。线程对象被创建后,其它线程调用了该对象的start()方法,从而来启动该线程。例如,thread.start()。处于就绪状态的线程,随时可能被CPU调度执行。
3. 运行状态(Running) : 线程获取CPU权限进行执行。需要注意的是,线程只能从就绪状态进入到运行状态。
4. 阻塞状态(Blocked) : 阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
(01) 等待阻塞 -- 通过调用线程的wait()方法,让线程等待某工作的完成。
(02) 同步阻塞 -- 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态。
(03) 其他阻塞 -- 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
5. 死亡状态(Dead) : 线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
图 1线程状态图
三、 start 和 run
线程中有两种方法:start 和 run
(1)start()方法用来启动一个新线程并且运行,该方法不能被重复调用
(2)Run()方法和普通的成员方法类似,单独调用run()方法会在当前线程中执行run()方法而不会启动一个新线程。
四、synchronized
当我们调用某对象的synchronized方法时,就获取了该对象的同步锁。例如,synchronized(obj)就获取了“obj这个对象”的同步锁。
不同线程对同步锁的访问是互斥的。也就是说,某时间点,对象的同步锁只能被一个线程获取到!通过同步锁,我们就能在多线程中,实现对“对象/方法”的互斥访问。 例如,现在有两个线程A和线程B,它们都会访问“对象obj的同步锁”。假设,在某一时刻,线程A获取到“obj的同步锁”并在执行一些操作;而此时,线程B也企图获取“obj的同步锁” —— 线程B会获取失败,它必须等待,直到线程A释放了“该对象的同步锁”之后线程B才能获取到“obj的同步锁”从而才可以运行。
synchronized 的三条规则:
第一条: 当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程对“该对象”的该“synchronized方法”或者“synchronized代码块”的访问将被阻塞。
第二条: 当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程仍然可以访问“该对象”的非同步代码块。
第三条: 当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程对“该对象”的其他的“synchronized方法”或者“synchronized代码块”的访问将被阻塞。
五、线程等待与唤醒
这一个有点难理解, 写了几个代码,注释很详细。仔细看一下。
方法简介:(所有方法都是Object的方法)
notify()
唤醒在此对象监视器上等待的单个线程。注意这里只是进入了就绪状态,并没有running
notifyAll()
唤醒在此对象监视器上等待的所有线程。注意这里只是进入了就绪状态,并没有running
wait()
让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法”,当前线程被唤醒(进入“就绪状态”)。
wait(long timeout)
让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量”,当前线程被唤醒(进入“就绪状态”)。
wait(long timeout, int nanos)
让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量”,当前线程被唤醒(进入“就绪状态”)
(1)wait and notify
package waitAndnotify;/** * * (01) “主线程”通过 new ThreadA("t1") * 新建“线程t1”。随后通过synchronized(t1)获取“t1对象的同步锁”。然后调用t1.start()启动“线程t1”。 (02) * “主线程”执行t1.wait() 释放“t1对象的锁”并且进入“等待(阻塞)状态”。等待t1对象上的线程通过notify() 或 * notifyAll()将其唤醒。 (03) * “线程t1”运行之后,通过synchronized(this)获取“当前对象的锁”;接着调用notify()唤醒 * “当前对象上的等待线程”,也就是唤醒“主线程”。 (04) * “线程t1”运行完毕之后,释放“当前对象的锁”。紧接着,“主线程”获取“t1对象的锁”,然后接着运行。 * */public class WaitClass {public static void main(String[] args) {ThreadA t1 = new ThreadA("t1");synchronized (t1) {// 調用wait()時必須要有該對象的同步鎖/** * (1) * */System.out.println(Thread.currentThread().getName() + "start t1");/** * (2) * */t1.start();//运行t1 但是线程t1 start之后只是进入了就绪状态,并没有获取锁。 所以现在运行的还是主线程/** * (3) * */System.out.println(t1.getName());/** * (4) * */System.out.println(Thread.currentThread().getName() + "wait()");try {/** * Causes the current thread to wait until another thread * invokes the notify() method or the notifyAll() method for * this object. In other words, this method behaves exactly as * if it simply performs the call wait(0). The current thread * must own this object's monitor. The thread releases ownership * of this monitor and waits until another thread notifies * threads waiting on this object's monitor to wake up either * through a call to the notify method or the notifyAll method. * The thread then waits until it can re-obtain ownership of the * monitor and resumes execution. * “当前线程”在调用wait()时,必须拥有该对象的同步锁。该线程调用wait()之后, * 会释放该锁;然后一直等待直到“其它线程”调用对象的同步锁的notify()或notifyAll()方法。 * 然后,该线程继续等待直到它重新获取“该对象的同步锁”,然后就可以接着运行。 */// t1.wait() 是当前线程,即主线程 wait() 而不是t1线程wait()/** * (5) * */t1.wait();//主线程wait 释放锁,讲锁交给t1,开始运行t1} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}/** * (10) * * *///主线程获得锁System.out.println(Thread.currentThread().getName() + "continue");while (true) {t1.notify();System.out.println("2");try {t1.wait();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}}class ThreadA extends Thread {public ThreadA(String name) {super(name);}@Overridepublic void run() {synchronized (this) {/** * (6) * */System.out.println(Thread.currentThread().getName() + "call notify");while (true) {/** * (6) * *///通知wait的线程进入就绪状态,但是此时还没有释放锁this.notify();/** * (7) * */System.out.println("1");try {/** * 8 * */System.out.println(Thread.currentThread().getName() +" wait");//t1 wait 释放锁/** * 9 * */this.wait();Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}}
运行结果:
mainstart t1
t1
mainwait()
t1call notify
1
t1 wait
maincontinue
2
1
t1 wait
2
1
t1 wait
2
(2) wait(long timeout)
package waitAndnotify;public class WaitTimeOut {public static void main(String[] args) {ThreadB b1 = new ThreadB("b1");synchronized (b1) {System.out.println(Thread.currentThread().getName() + " start t1");b1.start();// 主线程等待t1通过notify()唤醒 或 notifyAll()唤醒,或超过3000ms延时;然后才被唤醒。System.out.println(Thread.currentThread().getName() + " call wait ");try {b1.wait(3000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println(Thread.currentThread().getName() + " continue");}}}class ThreadB extends Thread {ThreadB(String name) {super(name);}public void run() {System.out.println(Thread.currentThread().getName() + " run ");while (true) {try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println(Thread.currentThread().getName());;}}}
运行结果:
main start t1
main call wait
b1 run
b1
b1
b1
(3秒后打印continue)
main continue
b1
b1
b1
(3) notifyAll()
public class NotifyAll {private static Object obj = new Object();public static void main(String args[]) {ThreadC c1 = new ThreadC("c1");ThreadC c2 = new ThreadC("c2");ThreadC c3 = new ThreadC("c3");c1.start();c2.start();c3.start();System.out.println("all started");try {Thread.sleep(2000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}synchronized (obj) {System.out.println("going to notifyall");obj.notifyAll();}}static class ThreadC extends Thread {ThreadC(String name) {super(name);}@Overridepublic void run() {synchronized (obj) {System.out.println(Thread.currentThread().getName() + "wait");try {obj.wait();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println(Thread.currentThread().getName()+ "continue");}}}}
运行结果:
all started
c1wait
c2wait
c3wait
两秒后
going to notifyall
c3continue
c2continue
c1continue
为什么wait notify 等方法属于Object?
Object中的wait(), notify()等函数,和synchronized一样,会对“对象的同步锁”进行操作。
wait()会使“当前线程”等待,因为线程进入等待状态,所以线程应该释放它锁持有的“同步锁”,否则其它线程获取不到该“同步锁”而无法运行!
OK,线程调用wait()之后,会释放它锁持有的“同步锁”;而且,根据前面的介绍,我们知道:等待线程可以被notify()或notifyAll()唤醒。现在,请思考一个问题:notify()是依据什么唤醒等待线程的?或者说,wait()等待线程和notify()之间是通过什么关联起来的?答案是:依据“对象的同步锁”。
负责唤醒等待线程的那个线程(我们称为“唤醒线程”),它只有在获取“该对象的同步锁”(这里的同步锁必须和等待线程的同步锁是同一个),并且调用notify()或notifyAll()方法之后,才能唤醒等待线程。虽然,等待线程被唤醒;但是,它不能立刻执行,因为唤醒线程还持有“该对象的同步锁”。必须等到唤醒线程释放了“对象的同步锁”之后,等待线程才能获取到“对象的同步锁”进而继续运行。
总之,notify(), wait()依赖于“同步锁”,而“同步锁”是对象锁持有,并且每个对象有且仅有一个!这就是为什么notify(), wait()等函数定义在Object类,而不是Thread类中的原因。
(未完待续。。。)
- java学习笔记--Thread
- java学习笔记-Thread
- Java Thread学习
- java Thread 学习
- 【Java】Thread学习笔记
- java学习之Thread
- 【java】Thread 学习小结
- java.lang.Thread学习笔记
- Java Thread学习历程一
- Java Thread学习之二
- Java Thread学习之三
- Java Thread学习之四
- Java Thread学习之五
- Java Thread学习之六
- Java Thread学习之七
- Java Thread 学习笔记1
- java Thread学习(基础)
- java Thread学习(共享资源)
- Word Ladder II
- 9.6 print out all valid combinations of n-pairs of parentheses
- JS中undefined、null以及NaN之间的区别,以及对象属性赋值的面试题
- Tripadvisor 面经解答 -持续更新ing
- Ubuntu14.04上Fig出现Couldn’t connect to Docker daemon …问题
- java Thread 学习
- Ubuntu 14.04 上 Fig 出现 client and server don’t have same version 问题及解决办法
- 【BZOJ 2819】 Nim
- BZOJ 1778 Usaco2010 Hol Dotp 驱逐猪猡 期望DP+高斯消元
- 【BZOJ 2597】 [Wc2007]剪刀石头布
- Codeforces Round #290 (Div. 2)(A,B,C)
- poj3691--DNA repair(AC自动机+dp)
- warning LNK4075: 忽略”/EDITANDCONTINUE”(由于”/INCREMENTAL:NO”规范)
- Longest Palindromic Substring