一 实现生产者/消费者两个线程交替执行
我们以生产面包线程 和 消费面包线程做例子
面包类 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);
}
}
}
原文: