java学习之浅谈多线程3--线程间协作
来源:互联网 发布:nba20162017数据统计 编辑:程序博客网 时间:2024/05/09 11:50
通过保证临界区上多个线程的相互排斥,线程同步完全可以避免竞争状态的发生,但是有时还需要线程之间的协作。有两种方式可用于线程间的通信。
1.使用条件Condition
Condition接口:
+await():void 当前线程等待直到发生某个条件+signal():void 唤醒一个等待线程+signalAll():Condition 唤醒所有等待线程
条件是通过调用Lock对象的newCondition()方法而创建的对象,为了使用条件,必须首先获取锁,await()方法让线程等待并且自动释放条件上的锁,一旦条件正确,线程重新获取锁并且继续执行。创建了条件,该对象就可以使用await(),signal()和signalAll()方法。
考虑典型的消费者/生产者例子。假设使用缓冲区储存整数。缓冲区的大小是受限的。缓冲区提供write(int)方法将一个int值添加到缓冲区中,还提供方法read()从缓冲区中读取和删除一个int值为了同步这个操作,使用具有两个条件的锁:notEmpty(即缓冲区非空)和notFull(即缓冲区未满)。当任务向缓冲区添加一个int时,如果缓冲区是满的,那么任务将会等待notFull状态。当任务从缓冲区中删除一个int时,如果缓冲区是空的,那么任务将等待notEmpty状态。代码如下:
import java.util.LinkedList;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class ConsumerProducer { private static Buffer buffer = new Buffer(); //创建缓冲区 public static void main(String[] args) { //创建线程池 ExecutorService executor = Executors.newFixedThreadPool(2); executor.execute(new ProducerTask()); executor.execute(new ConsumerTask()); executor.shutdown(); } private static class ProducerTask implements Runnable { @Override public void run() { try { int i = 1; while(true) { System.out.println("Producer writes " + i) ; buffer.write(i++); Thread.sleep((int)(Math.random() * 10000)); } } catch (InterruptedException e) { } } } private static class ConsumerTask implements Runnable { @Override public void run() { try { while(true) { System.out.println("\t\t\tConsumer reads " + buffer.read()); Thread.sleep((int)(Math.random() * 10000)); } } catch (InterruptedException e) { } } } /** * 创建内部类Buffer作为缓冲区 * @author zx * */ private static class Buffer { private static final int CAPACITY = 1; //缓冲区的大小 private LinkedList<Integer> queue = new LinkedList<Integer>(); private static Lock lock = new ReentrantLock(); //创建一个锁 //创建两个条件 private static Condition notEmpty = lock.newCondition(); //缓冲区非空 private static Condition notFull = lock.newCondition(); //缓冲区未满 public void write(int value) { lock.lock(); //获得锁 try { while(queue.size() == CAPACITY) { System.out.println("Wait for notFull condition"); notFull.await(); //暂停当前线程,等待notFull条件 } queue.offer(value); //将整数value加入缓冲区 notEmpty.signal(); //唤醒等待notEmpty条件的线程 } catch (InterruptedException e) { } finally { lock.unlock(); //释放锁 } } @SuppressWarnings("finally") public int read() { int value = 0; lock.lock(); //获得锁 try { while(queue.isEmpty()) { System.out.println("\t\tWait for notEmpty condition"); notEmpty.await(); //暂停线程等待notEmpty条件 } value = queue.remove(); //从缓冲区删除一个整数 notFull.signal(); //唤醒等待notFull条件的线程 } catch (InterruptedException e) { } finally { lock.unlock(); //释放锁 return value; } } }}
2.使用阻塞队列
阻塞队列在试图向一个满队列添加元素或者从空队列中删除元素时会导致线程阻塞。BlockingQueue接口扩展java.util.Queue,并且提供同步的put和take方法向队列头添加元素,以及从队列尾删除元素。
Java支持三个具体的阻塞队列ArrayBlockingQueue、LinkedBlockingQueue和PriorityBlockingQueue。
ArrayBlockingQueue使用数组实现阻塞队列。必须指定一个容量或者可选的公平性来构造ArrayBlockingQueue。
LinkedBlockingQueue使用链表实现阻塞队列。可以创建不受限的或者受限的LinkedBlockingQueue。
PriorityBlockingQueue是优先队列,可以创建不受限的或者受限的优先队列。
下面的程序使用ArrayBlockingQueue来简化上面的生产者/消费者程序。创建一个ArrayBlockingQueue来存储整数,生产者线程将一个整数放入队列中,而消费者线程从队列中取走一个整数。
import java.util.concurrent.ArrayBlockingQueue;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class ConsumerProducerUsingBlockingQueue { //创建buffer用来存储整数 private static ArrayBlockingQueue<Integer> buffer = new ArrayBlockingQueue<Integer>(2); public static void main(String[] args) { //创建线程池 ExecutorService executor = Executors.newFixedThreadPool(2); executor.execute(new ProducerTask()); executor.execute(new ConsumerTask()); executor.shutdown(); } private static class ProducerTask implements Runnable { @Override public void run() { try { int i = 1; while(true) { System.out.println("Producer writes " + i); buffer.put(i++); //向队列添加元素 Thread.sleep((int)(Math.random() * 10000)); } } catch (InterruptedException e) { } } } private static class ConsumerTask implements Runnable { @Override public void run() { try { while(true) { //从队列删除元素 System.out.println("\t\t\tConsumer reads " + buffer.take()); Thread.sleep((int)(Math.random() * 10000)); } } catch (InterruptedException e) { } } }}
- java学习之浅谈多线程3--线程间协作
- Java 多线程之线程间协作
- Java多线程之线程协作
- 多线程:线程间协作
- java学习之浅谈多线程2--线程同步
- java Thread学习(线程间协作)
- Java并发之线程间的协作
- Java线程学习笔记之线程协作(通信)
- Java多线程之线程间协作 notify与wait的使用
- 浅谈java多线程之创建线程方式
- Java多线程(3):使用Condition中的await、signal进行线程间协作
- java多线程学习之创建线程与线程间通信
- java学习之浅谈多线程1
- java学习之浅谈多线程4--SwingWorker
- Java中的线程间协作
- JAVA线程间协作:Condition
- 多线程之浅谈线程概念
- Java多线程实践之—协作
- 仿网易新闻APP底部菜单栏
- 各种好博客
- 快乐
- mysql上机作业4
- PopUpWindow使用详解(一)——基本使用
- java学习之浅谈多线程3--线程间协作
- STM8四路PWM配置
- 关于查看jdk32位还是64位的超简单方法
- Hibernate: org.hibernate.exception.SQLGrammarException: could not insert: 错误
- 插入排序
- Android的Recovery快速汉化
- postgresql 写存储过程传入的参数为字符串('4,5,6,8,9,10')个数不确定时,如何一次性删除
- SVN+Nginx自动部署脚本
- Ubuntu 14.04 安装Apache、MySQL、PHP、JDK7、Tomcat7、vsFTPd、Open SSH Server快速步骤