下面的例子模拟了一个生产者消费者的同步场景,在生产者生产的时候加入了仓库的容量和当前放置数的比较,注释写的很清楚,有问题请留言
需要注意的是
1.wait方法会释放当前同步块的锁,
2.notifyAll wait notify方法都要在同步块或者方法中调用
3.notifyAll 只是唤醒所有在锁上等待的线程,但是这些线程被唤醒后也会去竞争锁,只有一个线程能拿到锁,知道这个线程退出同步块,其他线程才能继续拿到锁运行,如此往复,可参考http://zhidao.baidu.com/link?url=F5NOESI9MbShg90JTHRthubuQVaeu7QksUwzGYUzWy-H0ePlu5uWs9_DYkDXJngggeT3A2wrE4GpbFZINqPAttKbGgGoTORKNsI87G4IFLC
public class ThreadTest {
String flag = "flag";
/**
* 仓库
*
* @author jinjing
*
*/
class WareHouse {
private int num;
private int max_num = 100;
public WareHouse(int num, int max_num) {
this.num = num;
this.max_num = max_num;
}
public void add(int number) {
// 如果要生产的数量大于仓库的容量则直接退出
if (number > max_num) {
System.out.println("number is too big");
return;
}
synchronized (flag) {
// 相加大于仓库的容量则等待10秒钟
if ((num + number) > max_num) {
System.out.println(Thread.currentThread().getName()
+ " wait for get");
try {
this.wait(1000);
} catch (Exception e) {
e.printStackTrace();
}
}
// 如果还大于仓库的容量则直接取消操作
if ((num + number) > max_num) {
System.out.println(Thread.currentThread().getName()
+ " add cancel warehouse have " + num);
return;
}
// 仓库容量增加
num = num + number;
System.out.println(Thread.currentThread().getName()
+ " sucess add " + number + " and warehouse have "
+ num);
// 唤醒所有在WareHouse实例上等待的线程,但是同一时刻只有一个线程拥有锁,直到拥有锁的线程退出synchronized块
flag.notifyAll();
}
}
public void get(int number) {
if (number > max_num) {
System.out.println("get number is too big");
return;
}
// 获取锁,拿产品,若产品不够则等待
synchronized (flag) {
while ((num - number) < 0) {
try {
System.out.println(Thread.currentThread().getName()
+ " " + System.currentTimeMillis()
+ " wait for add");
// 会释放flag的锁,其他线程将进来
flag.wait();
// notifyall唤醒所有线程,但是一个时刻只有一个线程拥有flag的锁资源,直到退出synchronized
System.out.println("awake "
+ System.currentTimeMillis() + ":"
+ Thread.currentThread().getName()
+ " now num-number=" + (num - number));
} catch (Exception e) {
e.printStackTrace();
}
}
try {
System.out.println(System.currentTimeMillis() + ":"
+ Thread.currentThread().getName());
Thread.sleep(3000);
} catch (Exception e) {
e.printStackTrace();
}
// 拿产品
num = num - number;
System.out.println(Thread.currentThread().getName()
+ " sucess get " + number + " and warehouse have "
+ num);
// 唤醒所有在WareHouse实例上等待的线程
flag.notifyAll();
}
}
}
/**
* 生产者
*
* @author jinjing
*
*/
class Producter implements Runnable {
int num;
WareHouse wareHouse;
public Producter(int num, WareHouse wareHouse) {
this.num = num;
this.wareHouse = wareHouse;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()
+ " producter add:" + num);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 开始生产
wareHouse.add(num);
}
}
/**
* 消费者
*
* @author jinjing
*
*/
class Consumer implements Runnable {
private volatile int num = 0;
WareHouse wareHouse;
public Consumer(int num, WareHouse wareHouse) {
this.num = num;
this.wareHouse = wareHouse;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()
+ " consumer get:" + num);
// 开始消费
wareHouse.get(num);
}
}
public void test() {
// 初始化一个仓库,仓库当前物品数为0,仓库容量为100
WareHouse wareHouse = new WareHouse(0, 100);
// 一个消费者,需要取10个货物
Consumer consumer = new Consumer(10, wareHouse);
// 一个生产者,需要放30个货物
Producter producter = new Producter(10, wareHouse);
// 一个生产者,需要放100个货物
// Producter producter1 = new Producter(10, wareHouse);
Thread t1 = new Thread(consumer);
Thread t2 = new Thread(producter);
Thread t3 = new Thread(consumer);
Thread t4 = new Thread(producter);
Thread t5 = new Thread(consumer);
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
}
public static void main(String[] args) {
ThreadTest threadTest = new ThreadTest();
threadTest.test();
}
}