線程間通信Demo

一 實現生產者/消費者兩個線程交替執行

我們以生產麪包線程  和 消費麪包線程做例子

麪包類
public class Bread {
    //麪包個數
    private  int num;
    //麪包id
    private  int id;

    //生產麪包
    public  synchronized void creat(){
        //麪包不等於0 等待
        if(num!=0){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //數量等於 0 生產麪包
        num++;
        id++;
        System.out.println(Thread.currentThread().getName()+"生產了 id爲"+id+"的麪包");
        notify();//喚醒消費麪包的線程
    }

    public  synchronized  void consume(){
        if(num==0){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //有面包了  被喚醒
        //開始消費麪包
        num--;
        System.out.println(Thread.currentThread().getName()+"消費了 id爲"+id+"的麪包");
        notify();//麪包沒有了 喚醒生產麪包的線程
    }
}

 

消費者

public class Consumer extends Thread{

    private  Bread bread;

    public Consumer(Bread bread) {
        this.bread = bread;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            this.bread.consume();
        }
    }
}

生產者

public class Creater extends Thread {
    private Bread bread;

    public Creater(Bread bread) {
        this.bread = bread;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            this.bread.creat();
        }
    }
}

測試

public class TestBread {
    public static  void main(String[] args){
        Bread bread = new Bread();
        Consumer consumer = new Consumer(bread);
        Creater creater = new Creater(bread);

      consumer.start();
      creater.start();

    }
}

結果:

Thread-1生產了 id爲1的麪包
Thread-0消費了 id爲1的麪包
------省略-------
Thread-1生產了 id爲20的麪包
Thread-0消費了 id爲20的麪包

知識點:

1.synchronized修飾方法鎖住的是對象的本身,也是this。誰調用的方法,鎖住的就是那個對象。(main方法創建的bread對象)

2.wait,notify,notifyAll方法:

  作用導致線程進人等待狀態直到它被通知。隨機選擇一個在該對象上調用 wait 方法的線程, 解除其阻塞狀態。解除那些在該對象上調用 wait 方法的線程的阻塞狀態。

 注意:必須在同步代碼塊,或者是同步方法和cock和unlcok方法中間調用。

分析:在上述例子中,兩個synchronized方法鎖住的是同一個bread對象(同一對象鎖),因此wait和notify註冊在同一個對象鎖上。

 

二     三線程交替順序執行

1.notify/wait方法

public class Test1 {
    private  static  Object object = new Object();
    private static int count = 0;

    static  Thread A = new Thread(new Runnable() {
        @Override
        public void run() {
            while (true){
                synchronized (object){
                    if(count%3==0){
                        System.out.println("Thread A is run");
                        count++;
                        object.notifyAll();
                    }else {
                        try {
                            object.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    });

    static Thread B = new Thread(new Runnable() {
        @Override
        public void run() {
            while (true){
                synchronized (object){
                    if(count%3==1){
                        System.out.println("Thread B is run");
                        count++;
                        object.notifyAll();
                    }else {
                        try {
                            object.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    });

    static  Thread C = new Thread(new Runnable() {
        @Override
        public void run() {
            while (true){
                synchronized (object){
                    if(count%3==2){
                        System.out.println("Thread C is run");
                        count++;
                        object.notifyAll();
                    }else {
                        try {
                            object.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    });

    public  static  void  main(String[] args){
        long t1 = System.currentTimeMillis();
        A.start();
        B.start();
        C.start();
        while (true) {
            if (System.currentTimeMillis() - t1 > 5) {
                System.exit(0);
            }
        }
    }
}

2.使用Lock與Condition


public class Test2 {
    private static Lock lock = new ReentrantLock();
    private static int count = 0;
    static Condition c1 = lock.newCondition();
    static   Condition c2 = lock.newCondition();
    static Condition c3 = lock.newCondition();

   static Thread  A = new Thread(new Runnable(){
        @Override
        public void run() {
            while (true) {
                lock.lock();
                try {
                while (count % 3 != 0) {
                    c1.await();
                }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println("Thread A is run:"+System.currentTimeMillis());
                    count++;
                    c2.signal();

                lock.unlock();

            }
        }
    });

    static Thread  B  = new Thread(new Runnable(){
        @Override
        public void run() {
            while (true) {
                lock.lock();
                try {
                    while (count % 3 != 1) {
                        c2.await();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println("Thread B is run:"+System.currentTimeMillis());
                count++;
                c3.signal();

                lock.unlock();

            }
        }
    });

    static Thread  C = new Thread(new Runnable(){
        @Override
        public void run() {
            while (true) {
                lock.lock();
                try {
                    while (count % 3 != 2) {
                        c3.await();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println("Thread C is run:"+System.currentTimeMillis());
                count++;
                c1.signal();

                lock.unlock();

            }
        }
    });

    public  static void  main(String[] a){
        long t1 = System.currentTimeMillis();
        A.start();
        B.start();
        C.start();
        while (true){
            if(System.currentTimeMillis()-t1>10){
                System.exit(0);
            }
        }
    }
}

 

3 使用信號量Semaphore


public class ConcurrentPrint {
    // 共享資源個數都初始爲1
    private static Semaphore s1 = new Semaphore(1);
    private static Semaphore s2 = new Semaphore(1);
    private static Semaphore s3 = new Semaphore(1);
    Thread t1 = new Thread(new Runnable() {
        public void run() {
            while (true) {
                try {
                    s1.acquire();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println("A");
                s2.release();
            }
        }
    });
    Thread t2 = new Thread(new Runnable() {
        public void run() {
            while (true) {
                try {
                    s2.acquire();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println("B");
                s3.release();
            }
        }
    });
    Thread t3 = new Thread(new Runnable() {
        public void run() {
            while (true) {
                try {
                    s3.acquire();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println("C");
                s1.release();
            }
        }
    });
 
    public void fun() throws InterruptedException {
        // 先佔有輸出BC的線程的信號量計數
        // 則只能從輸出A的線程開始。獲取信號量A,然後釋放B-獲取B-釋放C-獲取C-釋放A,由此形成循環
        s2.acquire();
        s3.acquire();
        t2.start();
        t3.start();
        t1.start();
    }
 
    public static void main(String[] args) throws InterruptedException {
        ConcurrentPrint cp = new ConcurrentPrint();
        long t1 = System.currentTimeMillis();
        cp.fun();
        while (true) {
            if (System.currentTimeMillis() - t1 >= 10)
                System.exit(0);
        }
    }
}

原文:

https://blog.csdn.net/qq_26567507/article/details/82666852

https://www.cnblogs.com/Wenxu/p/7979023.html

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