循環打印ABC/AB最簡代碼

信號量的方式

這是比較推薦的一種方式,不用控制線程啓動的順序. 思路簡單,直接上代碼,若是須要增長打印次數也很方便.java

static class PrintSemaphore implements Runnable {
        String printValue;

        Semaphore selfSemaphore;

        Semaphore nextSemaphore;

        public void setSelfSemaphore(Semaphore selfSemaphore) {
            this.selfSemaphore = selfSemaphore;
        }

        public void setNextSemaphore(Semaphore nextSemaphore) {
            this.nextSemaphore = nextSemaphore;
        }

        public PrintSemaphore(String printValue) {
            this.printValue = printValue;
        }

        @Override
        public void run() {
            while (true) {
                try {
                    selfSemaphore.acquire();//獲取信號量,s - 1
                    System.out.println(printValue);
                    nextSemaphore.release();//釋放信號量,s + 1
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }


      public static void main(String[] args) {
        //信號量,用於控制同時允許訪問的線程數量
        Semaphore sA = new Semaphore(1);
        Semaphore sB = new Semaphore(0);
        Semaphore sC = new Semaphore(0);

        PrintSemaphore printSemaphoreA = new PrintSemaphore("A");
        PrintSemaphore printSemaphoreB = new PrintSemaphore("B");
        PrintSemaphore printSemaphoreC = new PrintSemaphore("C");

        printSemaphoreA.setSelfSemaphore(sA);
        printSemaphoreA.setNextSemaphore(sB);

        printSemaphoreB.setSelfSemaphore(sB);
        printSemaphoreB.setNextSemaphore(sC);

        printSemaphoreC.setSelfSemaphore(sC);
        printSemaphoreC.setNextSemaphore(sA);


        ExecutorService exe = Executors.newCachedThreadPool();
        exe.execute(printSemaphoreB);
        exe.execute(printSemaphoreC);
        exe.execute(printSemaphoreA);


    }
複製代碼

使用synchronized

分析

看一個序列CABC,能夠得出:
CA, 打印A須要拿到前面C的鎖(表明C已經執行完),以及它本身的鎖.
AB,打印B須要拿到前面A的鎖(表明A已經執行完),以及它本身的鎖.
BC,打印A須要拿到前面B的鎖(表明B已經執行完),以及它本身的鎖.
只要打印ABC的線程,按順序啓動,即B啓動時A已經執行完一次,C啓動時B已經執行完一次.那麼序列的順序就是能夠保證的.ide

模擬

打印A線程先啓動,拿到C+A鎖,執行完後,釋放A鎖,並notifyAll.而後在C鎖上等待.
在間隔時間段後,打印B線程啓動,它請求A鎖並拿到,而後 拿到本身的B鎖,打印B.
,釋放B鎖,並notifyAll.而後在A鎖上等待.
注意此時:打印A線程 wait C,打印B線程 wait A
在間隔時間段後,打印C線程啓動,它請求B鎖並拿到,而後 拿到本身的C鎖,打印C.
,釋放C鎖,並notifyAll.而後在B鎖上等待.
這時咱們發現打印A線程的條件知足了,它能夠獲得C鎖和本身的A鎖.繼續循環
注意此時:打印B線程 wait A,打印C線程 wait B
打印ABCui

class PrintThreadSyn implements Runnable {
    // 打印值
    String value;
    // 前面的鎖
    Object preLock;

    public void setPreLock(Runnable runnable) {
        preLock = runnable;
    }

    public PrintThreadSyn(String value) {
        this.value = value;
    }

    @Override
    public void run() {

        synchronized (preLock) {
            while (true) {
                synchronized (this) {
                    System.out.println(value);
                    this.notifyAll();
                }
                try {
                    preLock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

public static void main(String[] args) throws InterruptedException {
        // ------------------------------synchronized--ABC-----------------------------
        // 循環打印ABC
        PrintThreadSyn threadA = new PrintThreadSyn("A");
        PrintThreadSyn threadB = new PrintThreadSyn("B");
        PrintThreadSyn threadC = new PrintThreadSyn("C");

        threadA.setPreLock(threadC);
        threadB.setPreLock(threadA);
        threadC.setPreLock(threadB);

        new Thread(threadA).start();
        Thread.sleep(500);
        new Thread(threadB).start();
        Thread.sleep(500);
        new Thread(threadC).start();
}
複製代碼

打印AB 只須要簡化代碼,對類無改動this

// 循環打印AB
        PrintThreadSyn threadA = new PrintThreadSyn("A");
        PrintThreadSyn threadB = new PrintThreadSyn("B");

       threadA.setPreLock(threadB);
       threadB.setPreLock(threadA);
			 
       new Thread(threadA).start();
			 Thread.sleep(500);
       new Thread(threadB).start();
複製代碼

ReentrantLock

思路是同樣的,用ReentrantLock+Condition代替syn+notify+wait.spa

class PrintThreadReentrantLock implements Runnable {
        String value;
        ReentrantLock lock;
        Condition preCondition;
        Condition selfCondition;

        public void setLock(ReentrantLock lock) {
            this.lock = lock;
        }

        public void setPreCondition(Condition condition) {
            this.preCondition = condition;
        }

        public void setSelfCondition(Condition condition) {
            this.selfCondition = condition;
        }

        public PrintThreadReentrantLock(String value) {
            this.value = value;
        }

        @Override
        public void run() {

            lock.lock();
            while (true) {

                System.out.println(value);
                selfCondition.signalAll();
                try {
                    preCondition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
            //lock.unlock();
        }
    }
public static void main(String[] args) throws InterruptedException {

		    PrintThreadReentrantLock threadA = new PrintThreadReentrantLock("A");
        PrintThreadReentrantLock threadB = new PrintThreadReentrantLock("B");
        PrintThreadReentrantLock threadC = new PrintThreadReentrantLock("C");

        ReentrantLock reentrantLock = new ReentrantLock();
        threadA.setLock(reentrantLock);
        threadB.setLock(reentrantLock);
        threadC.setLock(reentrantLock);


        Condition conditionA = reentrantLock.newCondition();
        Condition conditionB = reentrantLock.newCondition();
        Condition conditionC = reentrantLock.newCondition();
        threadA.setSelfCondition(conditionA);
        threadB.setSelfCondition(conditionB);
        threadC.setSelfCondition(conditionC);

        threadA.setPreCondition(conditionC);
        threadB.setPreCondition(conditionA);
        threadC.setPreCondition(conditionB);

        new Thread(threadA).start();
        Thread.sleep(500);
        new Thread(threadB).start();
        Thread.sleep(500);
        new Thread(threadC).start();
	}			
複製代碼

打印AB 只須要簡化代碼,對類無改動線程

PrintThreadReentrantLock threadA = new PrintThreadReentrantLock("A");
        PrintThreadReentrantLock threadB = new PrintThreadReentrantLock("B");

        ReentrantLock reentrantLock = new ReentrantLock();
        threadA.setLock(reentrantLock);
        threadB.setLock(reentrantLock);

        Condition conditionA = reentrantLock.newCondition();
        Condition conditionB = reentrantLock.newCondition();
        threadA.setSelfCondition(conditionA);
        threadB.setSelfCondition(conditionB);

        threadA.setPreCondition(conditionB);
        threadB.setPreCondition(conditionA);

        new Thread(threadA).start();
        Thread.sleep(500);
        new Thread(threadB).start();
複製代碼
相關文章
相關標籤/搜索