synchronize和生产者消费者模式
2015-12-26 14:40
393 查看
1. synchronize关键字
synchronize可以用来对方法或者代码块加锁,使得被加锁的代码在同一时间只能被单个线程访问。
Java中,每个对象都有一个对象锁,简单的说就是每个对象都可以作为一把锁来使用,将synchronized关键字作用于一个对象,就是将该对象作为锁来锁住一段代码。将synchronized作用于一个方法其实就是使用当前类的实例作为锁对象来锁住方法体中的代码。
2. wait()
锁对象的wait方法用来休眠一个线程并释放当前获取到的锁,同时将该线程加入该锁对象的等待列表。从方法名也可以看出,该方法执行的效果是“等待”,也就是等待某个条件满足后再唤醒当前线程继续执行。3. notify()和notifyAll()
锁对象的notify方法用来唤醒一个该对象等待列表中的线程。notifyAll用来唤醒等待列表中的所有线程。4. 生产者消费者模式
生产者消费者模式是经典的线程同步模式,生产者生产一定量的产品放在缓冲区中,消费者从缓冲区中取走产品消费。该模式的关键在于生产者只有在缓冲区未满时才能放入产品,否则需要等待;而消费者只有在缓冲区有数据时才能拿到产品并消费,否则也需要等待。用代码实现该模式,我们设计4个类,Producer、Consumer、Table、Food,Producer负责生产Food,生产出的Food放在Table上,Consumer从Table上拿走Food。
Food类:
public class Food { /** * food编号 */ private String no; public Food(String no) { this.no = no; } public String getNo() { return no; } public void setNo(String no) { this.no = no; } public String toString() { return "Food-"+no; } }
Producer类:
public class Producer implements Runnable { /** * 产品编号 */ private int mPrductNo = 0; /** * 产品存储缓冲区 */ private Table mTable; public Producer(Table table) { this.mTable = table; } private void produce(Table table) { synchronized (table) { mPrductNo++; Food food = new Food(String.valueOf(mPrductNo)); if (mTable.size() >= Table.MAX_SIZE) { try { table.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } table.putFood(food); table.notifyAll(); } } @Override public void run() { //生产100个产品 for (int i=0; i<100; i++) { produce(mTable); } } }
Consumer类:
public class Consumer implements Runnable { private Table mTable; public Consumer(Table table) { this.mTable = table; } private void consume(Table table) { synchronized (table) { if (table.size() <= 0) { try { table.wait(); } catch (InterruptedException e) { e.printStackTrace(); return; } } Food food = table.getFood(); table.notifyAll(); } } public void run() { for (int i=0; i <100; i++) { consume(mTable); } } }
Table类:
public class Table { public static final int MAX_SIZE = 10; private Queue<Food> tableQueue = new LinkedList<Food>(); public Object lock = new Object(); public void putFood(Food food) { tableQueue.offer(food); } public Food getFood() { return tableQueue.poll(); } public void show() { StringBuffer foodInTable = new StringBuffer(""); for (Food food : tableQueue) { foodInTable.append(food); foodInTable.append(","); } } public int size() { return tableQueue.size(); } }
Producer的produce方法 用来生产一个产品,由于Table也会被Consumer线程访问到并且修改其数据,所以在对Table进行put、get操作时需要加锁,我们使用Producer、Consumer共享的Table实例作为锁对象。在生产出Food后,我们需要判断table是否已被放满产品,如果已被放满,那么Producer线程就需要等待,等table中有空余空间时再放入产品,我们使用wait方法让Producer休眠并释放获取的锁。如果table中有空余空间,那么Producer会调用table的put方法放入一个产品,由于放入产品前table可能为空,那么会有Consumer在等待获取产品,所以放入产品后,Producer会调用table.notifyAll()去唤醒正在等待的Consumer对象。Consumer对象被唤醒后会调用table.getFood()方法获取产品。Consumer获取产品的代码和Producer类似。
相关文章推荐
- C#线程间不能调用剪切板的解决方法
- C#线程同步的三类情景分析
- C#获取进程或线程相关信息的方法
- C#停止线程的方法
- C#子线程更新UI控件的方法实例总结
- C#线程队列用法实例分析
- C++使用CriticalSection实现线程同步实例
- 基于C++实现的线程休眠代码
- VB读取线程、句柄及写入内存的API代码实例
- C#网络编程基础之进程和线程详解
- C#通过Semaphore类控制线程队列的方法
- C#多线程处理多个队列数据的方法
- C#实现线程安全的简易日志记录方法
- C#中线程同步对象的方法分析
- 深入多线程之:Wait与Pulse的使用详解
- ASP.NET线程相关配置
- 浅析linux环境下一个进程最多能有多少个线程
- 再谈JavaScript线程
- Java中使用synchronized关键字实现简单同步操作示例
- C#实现终止正在执行的线程