/**
*
*/
package com.wsheng.thread.communication;
/**
* 鸡蛋类
*
* @author Wang Sheng(Josh)
*
*/
public class Egg {
private double weight;
private double price;
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
}
/**
*
*/
package com.wsheng.thread.communication;
import java.util.ArrayList;
import java.util.List;
/**
* 线程间的通信: 放鸡蛋和取鸡蛋 - 生产者和消费者
* @author Wang Sheng(Josh)
*
*/
public class Basket {
/** 共享资源:篮子 */
private List eggs = new ArrayList();
/** 取鸡蛋*/
public synchronized Egg getEgg() {
while (eggs.size() == 0) {
try {
wait(); // 当前线程进入阻塞队列
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Egg egg = eggs.get(0);
// 清空篮子
eggs.clear();
// 唤醒阻塞队列的某线程到就绪队列
notify();
System.out.println("拿到鸡蛋");
return egg;
}
/** 放鸡蛋 */
public synchronized void putEgg(Egg egg) {
while (eggs.size() > 0) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
eggs.add(egg);
// 唤醒阻塞队列的某线程到就绪队列
notify();
System.out.println("放入鸡蛋");
}
static class PutThread extends Thread {
private Basket basket;
private Egg egg = new Egg();
public PutThread(Basket basket) {
this.basket = basket;
}
public void run() {
basket.putEgg(egg);
}
}
static class GetThread extends Thread {
private Basket basket;
public GetThread(Basket basket) {
this.basket = basket;
}
public void run() {
basket.getEgg();
}
}
public static void main(String[] args) {
Basket basket = new Basket();
for (int i = 0; i < 10; i++) {
new PutThread(basket).start();
new GetThread(basket).start();
}
}
}
输出结果:
放入鸡蛋
拿到鸡蛋
放入鸡蛋
拿到鸡蛋
放入鸡蛋
拿到鸡蛋
放入鸡蛋
拿到鸡蛋
放入鸡蛋
拿到鸡蛋
放入鸡蛋
拿到鸡蛋
放入鸡蛋
拿到鸡蛋
放入鸡蛋
拿到鸡蛋
放入鸡蛋
拿到鸡蛋
程序开始,A线程判断篮子是否为空,放入一个鸡蛋,并且唤醒在阻塞队列的一个线程,阻塞队列为空;假设CPU又调度了一个A线程,篮子非空,执行等待,这 个A线程进入阻塞队列;然后一个B线程执行,篮子非空,取走鸡蛋,并唤醒阻塞队列的A线程,A线程进入就绪队列,此时就绪队列就一个A线程,马上执行,放 入鸡蛋;如果再来A线程重复第一步,再来B线程重复第二步,整个过程就是生产者(A线程)生产鸡蛋,消费者(B线程)消费鸡蛋。
这个例子中,同步(互斥)的资源是一个实实在在的篮子对象,其实,共享资源也可以是一个简单的变量,如下面的例子,共享资源是一个bool变量。
例: 子线程循环10次,然后主线程循环100次,如此循环100次。子循环执行时主循环不能执行,主循环执行时子循环也不能执行。
/**
*
*/
package com.wsheng.thread.synchronize;
/**
* @author Wang Sheng(Josh)
*
*/
public class LoopThreadTest {
public static void main(String[] args) {
final Loop loopObj = new Loop();
new Thread(new Runnable() {
public void run() {
execute(loopObj, "sub");
}
}).start();
execute(loopObj, "main");
}
public static void execute(Loop loop, String threadType) {
for (int i = 0; i < 100; i++) {
try {
if ("main".equals(threadType)) {
loop.mainThread(i);
} else {
loop.subThread(i);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Loop {
private boolean isSubThread = true;
public synchronized void mainThread(int loop) throws InterruptedException {
while (isSubThread) {
this.wait();
}
for (int i = 0; i < 100; i++) {
System.out.println("main thread sequence of " + i + ", loop of " + loop);
}
isSubThread = true; // 主线程执行完毕,由子线程来执行
this.notify(); // 唤醒阻塞队列中的子线程到就绪队列
}
public synchronized void subThread(int loop) throws InterruptedException {
while (!isSubThread) {
this.wait();
}
for (int i = 0; i < 10; i++) {
System.out.println("sub thread sequence of " + i + ", loop of " + loop);
}
isSubThread = false; // 子线程执行完毕,由主线程来执行
this.notify(); // 唤醒阻塞队列中的主线程到就绪队列
}
}
需要注意的是,在上面的例子中,在调用wait方法时,都是用while判断条件的,而不是if,在wait方法说明中,也推荐使用while,因为在某些特定的情况下,线程有可能被假唤醒,使用while会循环检测更稳妥。
分享到:
2014-05-10 23:52
浏览 6276
评论