1. 程式人生 > 實用技巧 >深信服 SANGFOR 裝置密碼恢復和配置備份恢復

深信服 SANGFOR 裝置密碼恢復和配置備份恢復

執行緒通訊

為什麼要進行執行緒通訊

把一個大的任務放到主執行緒的話,由於順序執行,會嚴重影響程式執行的效率。為了提高效率和併發度,可以將任務解耦為多個執行緒執行,比如一個執行緒接收資料,一個執行緒處理資料,這個時候,執行緒間就會出現互動,也就是執行緒通訊。

生產者消費者模型

執行緒通訊的關鍵應用場景就是生產者消費者問題

  • 生產者是負責生產資料的模組,生產產品後,要通知消費者消費
  • 消費者是負責處理資料的模組,消費產品後,需要通知生產者生產
  • Java提供了幾個用於執行緒通訊的方法
方法名 作用
wait() 表示執行緒一直等待,直到其他執行緒通知,與sleep不同,會釋放鎖
wait(long time out) 指定等待的毫秒數
notify() 喚醒一個處於等待狀態的執行緒
notifiyAll() 喚醒同一個物件上所有呼叫wait()方法的執行緒,優先級別高的執行緒優先排程

生產者消費者的兩種方法實現

管程法:

消費者不能直接使用生產者的資料,需要建立一個緩衝區生產者將生產好的資料放入到緩衝區中,消費者從緩衝區拿出資料。

package MultiProcess;


import javax.swing.text.AsyncBoxView;

//管程法:利用緩衝區解決
public class TestProduceConsumer {
    public static void main(String[] args) {
        SyContaner container = new SyContaner();
        new Producetor(container).start();
        new Consumer(container).start();
    }
}

//生產者
class Producetor extends Thread{
    SyContaner container;
    public Producetor(SyContaner container){
        this.container = container;
    }
    //生產


    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            container.push(new Chicken(i));
            System.out.println("生產第" + i + "只雞");
        }
    }
}

//消費者
class Consumer extends Thread{
    SyContaner container;
    public Consumer(SyContaner container){
        this.container = container;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("消費第" + container.pop().id + "只雞");
        }
    }
}

//產品
class Chicken{
    int id;
    public Chicken(int id){
        this.id = id;
    }
}
class SyContaner{
    Chicken[] chickens = new Chicken[10];
    int count = 0;
    //生產者生產產品
    public synchronized void push(Chicken chicken){
        //滿了,通知消費者消費產品
        if(count == chickens.length){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //沒有滿,生產者生產產品
        chickens[count] = chicken;
        count++;

        this.notifyAll();
    }
    //消費者消費產品
    public synchronized Chicken pop(){
        //沒有產品了,通知生產者去生產
        if(count == 0){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        //有產品,消費
        count--;
        Chicken chicken = chickens[count];
        this.notifyAll();

        return chicken;
    }
}
訊號燈法:

消費者可以直接使用生產者生產好的資料,不需要設定緩衝區,

只需要設定一個標誌位,用來控制生產者和消費者的狀態。

package MultiProcess;

public class TestProducerConsumer2 {
    public static void main(String[] args) {
        TV tv = new TV();
        new Player(tv).start();
        new Watcher(tv).start();
    }
}

class Player extends Thread{
    TV tv;
    public Player(TV tv){
        this.tv = tv;
    }
    @Override
    public void run(){
        for (int i = 0; i < 20; i++) {
            if(i % 2 == 0){
                this.tv.play("快樂大本營");
            }else{
                this.tv.play("抖音:記錄美好生活");
            }
        }
    }
}

class Watcher extends Thread{
    TV tv;
    public Watcher(TV tv){
        this.tv = tv;
    }
    @Override
    public void run(){
        for (int i = 0; i < 20; i++) {
            tv.watch();
        }
    }
}

//產品-->節目
class TV{
    String voice;
    boolean flag = true;  //true代表需要生產者生產

    public synchronized void play(String voice){

        if(!flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        System.out.println("演員表演了:" + voice);

        this.voice = voice;
        this.flag = !this.flag; //不能繼續表演了,要等別人看完,通知消費者執行緒
        this.notifyAll();
    }

    public synchronized void watch(){
        if(flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        System.out.println("觀看了:" + voice);

        this.flag = !this.flag;
        this.notifyAll();
    }
}