线程间的同步控制问题

在多线程的程序中,除了要放置资源冲突外,还要保证线程的同步。

通过生产者消费者模型来验证线程的同步和资源共享问题。

假设有一个生产者Producer,一个消费者Consumer

生产者产生0~9的整数,将他们存储在Box中。要求生产者生产一个数字,消费者取得一个数字,这就涉及到了线程的同步的问题。

这个问题可以通过两个线程实现生产者和消费者,它们共享Box对象。如果不加控制就得不到预期的效果。

1. 不同步的设计

//需要被共享的Box对象
public class Box {
	private int data;
	public synchronized void put(int value){
		data = value;
	}
	public synchronized int get(){
		return data;
	}
}

//测试类
public class ProducerConsumerTest {
	public static void main(String[] args) {
		Box box = new Box();
		Producer producer = new Producer(box);
		Consumer consumer = new Consumer(box);
		producer.start();
		consumer.start();
	}

	static class Producer extends Thread {
		// 被共享的对象
		private Box box;

		public Producer(Box c) {
			box = c;
		}

		@Override
		public void run() {
			for (int i = 0; i < 10; i++) {
				box.put(i);
				System.out.println("Producer put: " + i);
				try {
					sleep((int) Math.random() * 100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}

	static class Consumer extends Thread {
		private Box box;

		public Consumer(Box c) {
			box = c;
		}

		@Override
		public void run() {
			int value = 0;
			for (int i = 0; i < 10; i++) {
				value = box.get();
				System.out.println("Consumer get: " + value);
			}
		}
	}
}


某次执行结果:

Producer put: 0
Consumer get: 0
Consumer get: 0
Consumer get: 0
Consumer get: 0
Consumer get: 0
Consumer get: 0
Consumer get: 0
Consumer get: 0
Consumer get: 0
Consumer get: 0
Producer put: 1
Producer put: 2
Producer put: 3
Producer put: 4
Producer put: 5
Producer put: 6
Producer put: 7
Producer put: 8
Producer put: 9

从执行结果可以看出,尽管使用了synchronized关键字实现了对象锁,单这还不够。

如果生产者的速度比消费者速度快,那么在消费者还没来得及取出前一个数据的情况下,生产者又产生了新数据,于是消费者就会跳过前一个数据;

反之,如果消费者的速度比生产者的速度快,那么在生产者还没生产下一个数据前,消费者可能两次取出同一个数据,也就是类似本次执行结果这样

下面我们利用监视器模型来修改一下

2. 监视器模型

为了避免上述情况的发生,就必须使生产者线程想Box对象中存入数据与消费者线程从Box对象中去的数据同步。

为了达到这一目的,我们可以采用监视器模型,通过调用wait和notify方法实现同步。

修改代码如下:

public class MonitorBox {
	private int data;
	// 用来表示数据是否可用
	private boolean available = false;

	public synchronized void put(int value) {
		while (available == true) {
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		data = value;
		available = true;
		notifyAll();
	}

	public synchronized int get() {
		while (available == false) {
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		available = false;
		notifyAll();
		return data;
	}
}


public class ProducerConsumerTest {
	public static void main(String[] args) {
		MonitorBox box = new MonitorBox();
		Producer producer = new Producer(box);
		Consumer consumer = new Consumer(box);
		producer.start();
		consumer.start();
	}

	static class Producer extends Thread {
		// 被共享的对象
		private MonitorBox box;

		public Producer(MonitorBox c) {
			box = c;
		}

		@Override
		public void run() {
			for (int i = 0; i < 10; i++) {
				box.put(i);
				System.out.println("Producer put: " + i);
				try {
					sleep((int) Math.random() * 100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}

	static class Consumer extends Thread {
		private MonitorBox box;

		public Consumer(MonitorBox c) {
			box = c;
		}

		@Override
		public void run() {
			int value = 0;
			for (int i = 0; i < 10; i++) {
				value = box.get();
				System.out.println("Consumer get: " + value);
			}
		}
	}
}

某次执行结果

Producer put: 0
Consumer get: 0
Producer put: 1
Producer put: 2
Consumer get: 1
Consumer get: 2
Producer put: 3
Consumer get: 3
Producer put: 4
Consumer get: 4
Producer put: 5
Consumer get: 5
Producer put: 6
Consumer get: 6
Producer put: 7
Producer put: 8
Consumer get: 7
Consumer get: 8
Consumer get: 9
Producer put: 9
从上面结果可以看出,虽然仍存在消费者和生产者线程快慢的问题,但是生产者和消费者线程基本实现了同步。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值