1. 程式人生 > >Java三個執行緒迴圈列印

Java三個執行緒迴圈列印

先上效果圖: 

目錄

資源

測試

資源

這裡用了condition

執行流程:執行緒1執行完,讓執行緒2醒來工作;執行緒2執行完,讓執行緒3醒來工作;執行緒3執行完,讓執行緒1醒來工作

原理(都是按最壞的情況分析):

①一開始3個執行緒搶鎖,如果執行緒2和3搶到鎖,會進入等待(因為num=1),並釋放鎖,此時只有執行緒1可以拿鎖

②執行緒1開始執行,將num=2,並喚醒執行緒2,此時執行緒1和執行緒2競爭鎖,如果執行緒1搶到鎖,會進入等待,並釋放鎖,此時只有執行緒2可以拿鎖

③執行緒2開始執行,將num=3,並喚醒執行緒3,此時執行緒2和執行緒3競爭鎖,如果執行緒2搶到鎖,會進入等待,並釋放鎖,此時只有執行緒3

可以拿鎖

④執行緒3開始執行,將num=1,並喚醒執行緒1,此時執行緒3和執行緒1競爭鎖,如果執行緒3搶到鎖,會進入等待,並釋放鎖,此時只有執行緒1可以拿鎖

這樣就能保證三個執行緒迴圈執行了


import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Resource {
    //num=1就是執行緒1執行,num=2就是執行緒2執行,num=3就是執行緒3執行
    private int num = 1;
    private Lock lock = new ReentrantLock();//建立鎖物件
    private Condition condition1 = lock.newCondition();//條件1
    private Condition condition2 = lock.newCondition();//條件2
    private Condition condition3 = lock.newCondition();//條件3


    public void sub1() {
        try {
            lock.lock();//開啟鎖
            while (num != 1){//這裡jdk原始碼裡推薦用while,因為有可能出現虛假喚醒,所以要再次確認
                try {
                    condition1.await();//條件1執行緒等待,並釋放鎖
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //執行到這裡,說明num=1
            num=2;
            Thread.sleep(1000);
            System.out.println("執行緒1執行完畢");
            condition2.signal();//喚醒條件2執行緒
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();//釋放鎖
        }

    }


    public void sub2() {
        try {
            lock.lock();//開啟鎖
            while (num !=2) {//這裡jdk原始碼裡推薦用while,因為有可能出現虛假喚醒,所以要再次確認
                try {
                    condition2.await();//條件2執行緒等待,並釋放鎖
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //如果執行緒執行到這裡,說明num=2
            num=3;
            Thread.sleep(1000);
            System.out.println("執行緒2執行完畢");
            condition3.signal();//喚醒條件3執行緒
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();//釋放鎖
        }

    }

    public void sub3() {
        try {
            lock.lock();//開啟鎖
            while (num !=3) {//這裡jdk原始碼裡推薦用while,因為有可能出現虛假喚醒,所以要再次確認
                try {
                    condition3.await();//條件3執行緒等待,並釋放鎖
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //如果執行緒執行到這裡,說明num=3
            num=1;
            Thread.sleep(1000);
            System.out.println("執行緒3執行完畢");
            condition1.signal();//喚醒條件1執行緒
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();//釋放鎖
        }

    }
}

測試

public static void main(String[] args) {
        Resource resource = new Resource();
        //第一個執行緒
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    resource.sub1();
                }
            }
        }).start();
        //第二個執行緒
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    resource.sub2();
                }

            }
        }).start();
        //第三個執行緒
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    resource.sub3();
                }

            }
        }).start();
    }