1. 程式人生 > >用三個執行緒按順序迴圈列印abc 三個字母,比如abcabcabc

用三個執行緒按順序迴圈列印abc 三個字母,比如abcabcabc

執行緒類

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by Andrew  on 2017/3/22.
 */
public class PrintThread implements Runnable{
    private String symbol;
    private Condition conditionA =null;
    private int go = 0;
    private ReentrantLock lock =null;
    //使用原子類,本例中並沒有多大意義
    private static AtomicInteger i=new AtomicInteger(0);

    public PrintThread(String symbol, Condition conditionA,int go,ReentrantLock lock) {
        this.symbol = symbol;
        this.lock = lock;
        this.conditionA = conditionA;
        this.go = go;
    }
    @Override
    public void run() {
        while (true){
            lock.lock();
            try {
                while (i.get() % 3 != go) {
                    conditionA.await();
                }

            } catch (InterruptedException e) {
                        e.printStackTrace();
            }
            //防止過多輸出
            if (i.get()==10)break;
            System.out.println("result "+symbol);
            i.getAndIncrement();
//            System.out.println(i.get());
            //可以試試signalAll或signal區別,比較時建議去掉前面的break
            conditionA.signalAll();
            lock.unlock();

        }
    }
}


main函式

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

/**
 * Created by Andrew  on 2017/3/22.
 */
public class PrintLetter {
    private static ReentrantLock lock = new ReentrantLock();
    private static Condition conditionA = lock.newCondition();
    public static void main(String[] args) throws InterruptedException {
        new Thread(new PrintThread("A",conditionA,0,lock)).start();
        new Thread(new PrintThread("B",conditionA,1,lock)).start();
        new Thread(new PrintThread("C",conditionA,2,lock)).start();
    }

}

下面這種實現是我最初的想法但當時並沒能實現,這種方式我認為比較巧妙但存在兩大問題:

1.達到目的後仍有執行緒處於等待狀態。

2.由於執行環境可能達不到最終結果。主要原因是執行緒排程順序


/**
 * Created by Andrew  on 2017/3/26.
 */
public class MyThreadPrinter implements Runnable {
    private String name;
    private Object prev;
    private Object self;

    private MyThreadPrinter(String name, Object prev, Object self) {
        this.name = name;
        this.prev = prev;
        this.self = self;
    }

    @Override
    public void run() {
        int count = 10;
        while (count > 0) {
            synchronized (prev) {
                synchronized (self) {
                    System.out.print(name);
                    count--;

                    self.notify();
                }
                try {
                    prev.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }
    }

    public static void main(String[] args) throws Exception {
        Object a = new Object();
        Object b = new Object();
        Object c = new Object();
        MyThreadPrinter pa = new MyThreadPrinter("A", c, a);
        MyThreadPrinter pb = new MyThreadPrinter("B", a, b);
        MyThreadPrinter pc = new MyThreadPrinter("C", b, c);


        new Thread(pa).start();
        new Thread(pb).start();
        new Thread(pc).start();    }
}
錯誤排程順序:如果主執行緒在啟動A後,執行A,過程中又切回主執行緒,啟動了ThreadB,ThreadC,之後,由於A執行緒尚未釋放self.notify,也就是B需要在synchronized(prev)處等待,而這時C卻呼叫synchronized(prev)獲取了對b的物件鎖。這樣,在A呼叫完後,同時ThreadB獲取了prev也就是a的物件鎖,ThreadC的執行條件就已經滿足了,會列印C,之後釋放c,及b的物件鎖,這時ThreadB具備了執行條件,會列印B,也就是迴圈變成了ACBACB了