一 實現生產者/消費者兩個線程交替執行
我們以生產麪包線程 和 消費麪包線程做例子
麪包類 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);
}
}
}
原文: