1. 程式人生 > >傳統執行緒同步通訊synchronized

傳統執行緒同步通訊synchronized

1.典型的生產者消費者問題

    先生產再消費,A生產完後 通知B消費 B消費完後通知A 再生產 依次往復。

package com.yanghs.test.pro;

/**
 * @author yanghs
 * @Description:溝通資源
 * @date 2018/3/30 23:49
 */
public class Movie {
    private String pic;
    /*訊號燈 true生產者生產 false消費者消費*/
    private boolean flag = true;
    public synchronized void play(String pic) throws InterruptedException {
        if(!flag){
            wait();
        }
        this.pic = pic;
        /*生產完畢 更改訊號燈 為消費者*/
        System.out.println("生產完畢");
        this.flag = false;
        this.notify();

    }
    public synchronized void watch() throws InterruptedException {
        if(flag){
            wait();
        }
        System.out.println(pic);
        System.out.println("消費完畢");
        /*t通知生產者*/
        this.notify();
        this.flag = true;
    }
}

關鍵點 把生產者和消費者抽象為一個類裡面 便於加鎖和通訊  上面是抽象好的一個類

生產者

package com.yanghs.test.pro;

/**
 * @author yanghs
 * @Description:生產者
 * @date 2018/3/30 23:52
 */
public class Player implements Runnable {
    private Movie m;

    public Player(Movie m) {
        this.m = m;
    }

    @Override
    public void run() {
        for(int i=0; i<=20;i++){
            try {
                m.play("aaaaaaaaaa");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

消費者

package com.yanghs.test.pro;

/**
 * @author yanghs
 * @Description:消費者
 * @date 2018/3/30 23:52
 */
public class Watcher implements Runnable {
    private Movie m;

    public Watcher(Movie m) {
        this.m = m;
    }

    @Override
    public void run() {
        for (int i=0; i<=20;i++){
            try {
                m.watch();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

呼叫者

package com.yanghs.test.pro;

/**
 * @author yanghs
 * @Description:
 * @date 2018/3/30 23:59
 */
public class App {
    public static void main(String[] args) {
        Movie m = new Movie();

        Player p  = new Player(m);
        Watcher w = new Watcher(m);
        new Thread(p).start();
        new Thread(w).start();
    }
}

2.一個面試題

    有主執行緒和子執行緒,要求子執行緒先執行5次 後 主執行緒執行 5次 依次往復5次

分析:子執行緒主執行緒是有執行順序的 執行順序可以通過 join 和 synchronized wait notify實現 但是這裡又要求 這個動作要迴圈5次,就是  a>b>a>b... 顯然join不符合。所以應該向wait這邊靠。

    1)子執行緒和主執行緒需要相互通知執行 所以先抽象出邏輯程式碼 ab的通訊,synchronized加在方法上 表示鎖定呼叫這個方法的物件 下面的方法就表示鎖定 Business例項化的物件 

物件鎖是在一個類的物件上加的的鎖,只有一把,不管有幾個方法進行了同步。
這些同步方法都共有一把鎖,只要一個執行緒獲得了這個物件鎖,其他的執行緒就不能訪問該物件的任何一個同步方法。

class Business{
    volatile boolean flag = true;//子執行緒執行 true
    public synchronized void sub(){
        if(!flag){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        for(int i=0;i<=3;i++){
            System.out.println("子執行緒"+i);
        }
        flag = false;
        notify();
    }
    public  synchronized void main(){
        if(flag){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        for(int i=0;i<=3;i++){
            System.out.println("主執行緒"+i);
        }
        flag = true;
        notify();
    }
}

    2)呼叫

public class TraSynchronized {
    public static void main(String[] args) {
        /*建一個業務*/
        final Business b = new Business();
        /*新建一個子執行緒 並且開啟執行 業務中的sub()*/
        new Thread(new Runnable() {
            @Override
            public void run() {
                for(int i =0 ;i<=5;i++){
                    b.sub();
                }
            }
        }).start();
        /*主執行緒執行 main()*/
        for(int i =0 ;i<=5;i++){
            b.main();
        }

    }
}

實現效果