【Java多線程】(四)線程間通信

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方法來修改子線程繼承自父線程的值)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章