1.等待/通知機制
wait和notify都是object類的方法。
wait()是線程停止運行,notify()使停止的線程繼續運行。
在調用wait和notify時,必須獲得對象級鎖,因此必須在同步方法或者同步代碼塊中執行。
wait:釋放的對象鎖-->該鎖被其他線程獲取,-->獲取該鎖的線程調用notify並執行完畢釋放對象鎖-->原來調用wait方法的對象重新獲得對象鎖-->繼續執行
示例代碼:
MyThread1.java
package zzzztrhead;
public class MyThread1 extends Thread {
private Object lock;
public MyThread1(Object lock) {
super();
this.lock = lock;
}
@Override
public void run() {
synchronized (lock) {
try {
System.out.println("開始wait");
lock.wait();
System.out.println("結束wait");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
lock.wait();
System.out.println("結束wait");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
MyThread2.java:
package zzzztrhead;
public class MyThread2 extends Thread {
private Object lock;
public MyThread2(Object lock) {
super();
this.lock = lock;
}
@Override
public void run() {
synchronized (lock) {
System.out.println("開始notify");
lock.notify();
System.out.println("結束notify");
}
}
}
lock.notify();
System.out.println("結束notify");
}
}
}
Test:
package zzzztrhead;
public class WaitNotifyTest {
public static void main(String []args) throws InterruptedException{
Object lock=new Object();
MyThread1 t1=new MyThread1(lock);
t1.start();
Thread.sleep(3000);//main線程讓出cpu
MyThread2 t2=new MyThread2(lock);
t2.start();
}
}
執行結果:
開始wait
開始notify
結束notify
結束wait
由執行結果也可以看出:wait釋放對象鎖,notify不釋放,必須等待執行notify的同步方法或代碼塊執行完才釋放。
個人理解的:
wait釋放的對象鎖-->該鎖被其他線程獲取,-->獲取該鎖的線程調用notify並執行完畢釋放對象鎖-->原來調用wait方法的對象重新獲得對象鎖-->繼續執行
2.通過管道進行通信
1.PipedInputStream和PipedOutputStream(字節流)
2.PipedReader和PipedWriter(字符流)
*(outputStream.connect(inputStream);)
3.join方法:
作用:使所屬線程對象x正常執行run方法中的任務,使當前線程無線阻塞,等待線程x銷燬後再繼續執行線程z後面的代碼。
在內部使用wait方法進行等待,
源碼:
public final void join() throws InterruptedException {
join(0);
}
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
wait(0);//使調用join方法的線程等待
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
還有一點:
t1.wait(); // 不是使t1線程等待,而是當前執行wait的線程等待
4.ThreadLocal的使用
每個線程綁定自己的值,可以將ThreadLocal類比喻成全局存放數據的盒子,盒子中可以存儲每個線程的私有數據。
ThreadLocal源碼解析:https://www.cnblogs.com/dennyzhangdd/p/7978455.html#_label0_0
操作一個內部類對象ThreadLocalMap,key=當前線程,value=線程局部變量。數據結構以及get,擴容等等類似於hashmap,set解決衝突用的開放定址法。
InheritableThreadLocal可以讓子線程從父線程中取得值。(在線程初始化時,將賦值過去,可通過重寫childeVlue方法來修改子線程繼承自父線程的值)