Java线程间通信
来源:互联网 发布:威锋软件源地址 编辑:程序博客网 时间:2024/06/05 05:21
管道流
管道流分为管道输入流PipedInputStream和管道输出流PipedOutputStream,两者必须联合使用管道输入流内部有一个循环缓冲字节数组(以下称缓冲数组),默认大小是1024。管道输入流读取其缓冲数组的数据,管道输出流实际上是通过调用管道输入流的方法往缓冲数组写数据。当缓冲数组满了,管道输出流所在线程被阻塞。当缓冲数组为空,管道输入流所在线程被阻塞。不建议对这两个对象尝试使用单个线程,因为如果读或者写被阻塞,那么就会造成死锁。
管道输入流和管道输出流都有connect方法,这个方法将两个流连接起来,只要调用任意一个就可以,否则会报异常IOException("Already connected")。管道输出流的connect方法实际上是调用了管道输入流的connect方法。如果管道输出流所在的线程已经终止,那么管道输入流再去读取的话,就会报错。
public static void main(String[] args) throws Exception { final PipedInputStream pipedInputStream = new PipedInputStream(); final PipedOutputStream pipedOutputStream = new PipedOutputStream(); pipedInputStream.connect(pipedOutputStream); Thread inThread = new Thread() { @Override public void run() { try { while (true) { System.out.println("开始消费"); System.out.println("返回:" + pipedInputStream.read()); } } catch (Exception e) { e.printStackTrace(); } } }; Thread outThread = new Thread() { @Override public void run() { try { for (int i = 0; i < 3; i++) { Thread.sleep(1000); System.out.println("开始生产"); pipedOutputStream.write(new Random().nextInt(128)); } } catch (Exception e) { e.printStackTrace(); } } }; inThread.start(); outThread.start(); }
开始消费开始生产开始生产返回:45开始消费返回:23开始消费开始生产返回:6开始消费java.io.IOException: Write end deadat java.io.PipedInputStream.read(PipedInputStream.java:311)at Demo$1.run(Demo.java:23)
对象内部锁和内部条件
import java.util.Random;public class Demo { private class Production { /** * 下一个生产的产品的索引 */ private int in = 0; /** * 下一个消费的产品索引 */ private int out = -1; /** * 产品数组 */ private int[] ints = new int[1024]; /** * 生产 * * @param i */ public synchronized void produce(int i) { while (in == ints.length) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } ints[in] = i; out = in; in++; this.notifyAll(); } /** * 消费 * * @return */ public synchronized int comsume() { while (out < 0) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } int i = ints[out]; in = out; out--; this.notifyAll(); return i; } } /** * @param args */ public static void main(String[] args) { final Production production = new Demo().new Production(); Thread comsumeThread = new Thread() { @Override public void run() { while (true) { System.out.println("开始消费"); System.out.println("返回:" + production.comsume()); } } }; Thread produceThread = new Thread() { @Override public void run() { for (int i = 0; i < 10; i++) { try { Thread.sleep(1000); System.out.println("开始生产"); production.produce(new Random().nextInt(128)); } catch (InterruptedException e) { e.printStackTrace(); } } } }; comsumeThread.start(); produceThread.start(); }}
开始消费开始生产返回:110开始消费开始生产返回:11开始消费开始生产返回:73开始消费开始生产返回:18开始消费开始生产返回:43开始消费开始生产返回:100开始消费开始生产返回:47开始消费开始生产返回:43开始消费开始生产返回:101开始消费开始生产返回:62开始消费(这里阻塞了)
锁和条件
import java.util.Random;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.ReentrantLock;public class Demo { private class Production { /** * 锁 */ private ReentrantLock reentrantLock = new ReentrantLock(); /** * 条件对象 */ private Condition condition = reentrantLock.newCondition(); /** * 下一个生产的产品的索引 */ private int in = 0; /** * 下一个消费的产品索引 */ private int out = -1; /** * 产品数组 */ private int[] ints = new int[1024]; /** * 生产 * * @param i */ public void produce(int i) { reentrantLock.lock(); try { while (in == ints.length) { try { condition.await(); } catch (InterruptedException e) { e.printStackTrace(); } } ints[in] = i; out = in; in++; condition.signalAll(); } finally { reentrantLock.unlock(); } } /** * 消费 * * @return */ public int comsume() { reentrantLock.lock(); try { while (out < 0) { try { condition.await(); } catch (InterruptedException e) { e.printStackTrace(); } } int i = ints[out]; in = out; out--; condition.signalAll(); return i; } finally { reentrantLock.unlock(); } } } /** * @param args */ public static void main(String[] args) { final Production production = new Demo().new Production(); Thread comsumeThread = new Thread() { @Override public void run() { while (true) { System.out.println("开始消费"); System.out.println("返回:" + production.comsume()); } } }; Thread produceThread = new Thread() { @Override public void run() { for (int i = 0; i < 10; i++) { try { Thread.sleep(1000); System.out.println("开始生产"); production.produce(new Random().nextInt(128)); } catch (InterruptedException e) { e.printStackTrace(); } } } }; comsumeThread.start(); produceThread.start(); }}
阻塞队列
import java.util.Random;import java.util.concurrent.ArrayBlockingQueue;public class Demo { /** * @param args */ public static void main(String[] args) { final ArrayBlockingQueue<Integer> integers = new ArrayBlockingQueue<Integer>(1024); Thread comsumeThread = new Thread() { @Override public void run() { while (true) { try { System.out.println("开始消费"); System.out.println("返回:" + integers.take()); } catch (InterruptedException e) { e.printStackTrace(); } } } }; Thread produceThread = new Thread() { @Override public void run() { for (int i = 0; i < 10; i++) { try { Thread.sleep(1000); System.out.println("开始生产"); integers.put(new Random().nextInt(128)); } catch (InterruptedException e) { e.printStackTrace(); } } } }; comsumeThread.start(); produceThread.start(); }}
输出内容与对象内部锁和内部条件的例子一样。
如何终止消费者线程?
import java.util.Random;import java.util.concurrent.ArrayBlockingQueue;public class Demo { /** * @param args */ public static void main(String[] args) { final ArrayBlockingQueue<Integer> integers = new ArrayBlockingQueue<Integer>(1024); class ConsumeThread extends Thread { public ConsumeThread(ThreadGroup threadGroup, String name) { super(threadGroup, name); } @Override public void run() { while (!this.isInterrupted()) { try { System.out.println(Thread.currentThread().getName() + "返回:" + integers.take()); } catch (InterruptedException e) { e.printStackTrace(); this.interrupt(); } } } } final ThreadGroup threadGroup = new ThreadGroup("comsumeThreadGroup"); Thread comsumeThread1 = new ConsumeThread(threadGroup, "comsumeThread1"); Thread comsumeThread2 = new ConsumeThread(threadGroup, "comsumeThread2"); Thread produceThread = new Thread() { @Override public void run() { for (int i = 0; i < 10; i++) { try { Thread.sleep(1000); System.out.println("开始生产"); integers.put(new Random().nextInt(128)); } catch (InterruptedException e) { e.printStackTrace(); } }while (integers.size() != 0) { } threadGroup.interrupt(); } }; comsumeThread1.start(); comsumeThread2.start(); produceThread.start(); }}
开始生产comsumeThread2返回:57开始生产comsumeThread1返回:74开始生产comsumeThread2返回:97开始生产comsumeThread1返回:34开始生产comsumeThread2返回:99开始生产comsumeThread1返回:8开始生产comsumeThread2返回:6开始生产comsumeThread1返回:107开始生产comsumeThread2返回:45开始生产comsumeThread1返回:52java.lang.InterruptedExceptionat java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.reportInterruptAfterWait(AbstractQueuedSynchronizer.java:2017)at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2052)at java.util.concurrent.ArrayBlockingQueue.take(ArrayBlockingQueue.java:374)at Demo$1ConsumeThread.run(Demo.java:27)java.lang.InterruptedExceptionat java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.reportInterruptAfterWait(AbstractQueuedSynchronizer.java:2017)at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2052)at java.util.concurrent.ArrayBlockingQueue.take(ArrayBlockingQueue.java:374)at Demo$1ConsumeThread.run(Demo.java:27)
注意,捕获到InterruptedException时,要继续设置中断状态this.interrupt(),因为阻塞队列内部是使用可重入锁和条件的,当wait、await、sleep等方法阻塞过程中被中断时会抛出InterruptedException并且清除中断状态,所以要么往外抛出InterruptedException,要么在catch里继续设置中断状态而不能什么都不做。
阅读全文
0 0
- JAVA线程-线程间通信
- java 线程间通信
- java线程间通信
- Java线程间通信
- java线程间通信
- Java-线程间通信
- java线程间通信
- Java线程间通信
- java线程间通信
- java线程间通信
- Java线程间通信
- Java线程间通信
- Java线程间通信
- Java线程间通信
- Java线程间通信
- java-线程间通信
- Java线程间通信
- java线程间通信
- Java内存区域与内存溢出异常
- android从应用到驱动之—camera(2)---cameraHAL的实现
- SQLite学习第一天
- Emacs显示时间、隐藏菜单栏工具栏、关闭启动画面、高亮当前行
- Memento模式
- Java线程间通信
- 设置TextView的颜色
- formData详细介绍
- HashMap实现原理分析
- Oracle11g和oracle10g之间的导入/导出
- 没有下载券和财富值如何下载文库的资料
- 给网址结尾加上反斜杠
- 底部弹出框分享
- 如何用MindManager画树状思维导图