【JAVA書單】-《JAVA多線程核心技術》-第三章 線程間通信

此文是對《JAVA多線程編程核心技術》的一點總結,如果想要了解具體細節可以去看原書。

第三章 線程間通信

使用wait/notify實現線程間的通信

  • 方法wait()的作用是使當前執行代碼的線程進行等待,wait()方法是Object類的方法,該方法用來將當前線程置入“預執行隊列”中,並且在wait()所在的代碼行處停止執行,直到接到通知或中斷爲止。在調用wait()之前,線程必須獲得該對象的對象級別鎖,即只能在同步方法或同步塊中調用wait()方法。執行wait()方法後,當前線程釋放鎖
  • 如果調用wait()時沒有持有適當的鎖,則拋出IllegalMonitorStateException,它是RuntimeException的一個子類,因此,不需要try-catch語句捕獲異常。
  • 方法notify()也要在同步方法或同步代碼塊中調用,即在調用前,線程也必須獲得該對象的對象級別鎖。
  • notify()用來通知那些可能等待該對象的對象鎖的其他線程,如果有多個線程等待,則由線程規劃器隨機挑選出一個呈wait狀態的線程,對其發出通知notify,並使它等待獲取該對象的對象鎖
  • 在執行notify()方法後,不會馬上釋放該對象鎖,要等到執行notify()方法的線程將程序執行完,當前線程纔會釋放鎖。

線程狀態

在這裏插入圖片描述

  • 生產者/消費者模式的實現

創建存儲值的對象

public class MyStack {
    private List list = new ArrayList<>();

   synchronized public void push() {
        try{
            while (list.size() == 1) {
                this.wait();
            }
            list.add("anyString=" + Math.random());
            this.notify();
            System.out.println("push=" + list.size());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    synchronized public String pop() {
       String returnValue = "";
       try {
           while (list.size() == 0) {
               System.out.println("pop操作中的:" + Thread.currentThread().getName() + " 線程呈wait狀態");
               this.wait();
           }
           returnValue = "" + list.get(0);
           list.remove(0);
           this.notify();
           System.out.println("pop=" + list.size());
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
       return returnValue;
    }
}

生產者

/**
 * 生產者
 */
public class P {
    private MyStack myStack;

    public P(MyStack myStack) {
        this.myStack = myStack;
    }


    public void pushService() {
      myStack.push();
    }
}

生產者線程

public class P_Thread extends Thread {
    private P p;

    public P_Thread(P p) {
        this.p = p;
    }

    @Override
    public void run() {
        while (true) {
            p.pushService();
        }
    }
}

消費者

/**
 * 消費者
 */
public class C {
    private MyStack myStack;

    public C(MyStack myStack) {
        this.myStack = myStack;
    }

    public void popService() {
        System.out.println("pop=" + myStack.pop());
    }
}

消費者線程

public class C_Thread extends Thread {
    private C r;

    public C_Thread(C r) {
        this.r = r;
    }

    @Override
    public void run() {
        while (true) {
            r.popService();
        }
    }
}

啓動類

public class Run {
    public static void main(String[] args) {
        MyStack myStack = new MyStack();
        P p1 = new P(myStack);
        P p2 = new P(myStack);
        P p3 = new P(myStack);
        P_Thread pThread1 = new P_Thread(p1);
        P_Thread pThread2 = new P_Thread(p2);
        P_Thread pThread3 = new P_Thread(p3);
        pThread1.start();
        pThread2.start();
        pThread3.start();
        C r1 = new C(myStack);
        C r2 = new C(myStack);
        C r3 = new C(myStack);
        C_Thread cThread1 = new C_Thread(r1);
        C_Thread cThread2 = new C_Thread(r2);
        C_Thread cThread3 = new C_Thread(r3);
        cThread1.start();
        cThread2.start();
        cThread3.start();
    }
}
  • 方法join的使用
    方法join的作用是使所屬的線程對象x正常執行run()方法中的任務,而使當前線程z進行無限期的阻塞,等待線程銷燬後再執行線程z後面的代碼。
  • ThreadLocal類的使用
    ThreadLocal類主要解決的是每個線程綁定自己的值,可以將ThreadLocal類比喻成全局存放數據的盒子,盒子中可以存儲每個線程的私有數據。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章