Java线程间的通信
来源:互联网 发布:iphone7plus在线软件 编辑:程序博客网 时间:2024/05/01 15:47
线程间的通信
1、当任务相互之间进行协作时,关键问题是实现这些任务之间的握手,为了实现这种握手,可以使用任务相同的基础特性:互斥;对于这些实现这些握手问题可以采用的方法:
①通过Object对象的wait()和notify()方法来安全实现;
②通过SE5并发类库中Condition对象的await()和signal()方法;
2、Object的wait、notify方法
1)wait、notify和sleep、yield的区别
①wait()可以使一个任务被挂起,对象上的锁被释放,而sleep、yield调用时对象上的锁不会被释放;
②wait、notify是基于Object的,而sleep、yield是基于Thread的;
③wait、notify只能在synchronized同步控制方法、或同步控制块中调用(因为需要同步控制锁),sleep、yield可以在费同步控制块中调用;
2)wait(milliseconds):调用对象的锁被挂起milliseconds, 之后对象从wait中恢复;
wait():调用对象的锁被释放,并无限等待下去,直到该对象调用了notify或notifyAll;
notifyAll():将调用对象上全部被挂起的任务恢复运行;
notify():将调用对象上一个被挂起的任务恢复,该任务的选择时任意,一般当多个任务使用相同的条件等待同一个锁,此时使用notify比起notifyAll效率更高;
3)示例代码
T1:
synchronized(sharedMonitor){
<setup condition for T2>;
sharedMonitor.notify();
}
T2:
synchronized(shareedMonitor){
while(somwCondition){
//point1;
shareMonitor.wait();
}
}
//T1是通知T2的线程,T2在运行是由于某种条件而挂起,而T1进行相应的处理后改变该条件,同时释放shareMonitor的锁,是T1恢复运行;
/*如果T2是以下的方式,可能会错失T1的通知,在T2 point1处,由T1处理后的条件状态可能已经被修改,从而可能会导致死锁
while(someCondition){
//point1;
synchronized(sharedMonitor)
shareMonitor.wait();
}*/
实例:仿真延时多输线程输入开关(响应每一个任务):
class Light{ private boolean switch = false; //线程控制条件 public void turnOn() throws InterruptedException{ //turn on switch synchronized(this){ while(switch == true) wait(); TimeUnit.SECONDS.sleep(2); //at lest run 3s; switch = true; notifyAll(); } } public void trunOff() throws InterruptedException{ //turn off switch synchronized(this){ while(switch == false) wait(); switch = true; notify(); } }}//Testclass Demo{ public static void main() throws InterruptedException { Switch lightSwitch = new Switch(); Scanner input = new Scanner(System.in); ExecutorService exec = Executor.newCachedThreadPool(); while(!Thread.interrupted()){ in = nextBoolean(); if(in){ exec.execute(new Runnable(){ public void run(){ lightSwitch.turnOn(); }}); } else if(!in){ exec.execute(new Runnable(){ public void run(){ lightSwitch.turnOff(); }}); } } }}
3、Condition的await、signal操控Lock的行为
1)对lock绑定一个或多个Condition条件类,在不同的代码块中通过Condition来操作lock;
一个lock可以对应拥有多个condition,每个condition的状态对应各自的状态控制,共同决定lock的状态;
2)使用lock的condition条件进行线程通信时注意要检测InterruptedException异常;
3) signal( ):唤醒任意一个等待该条件的线程;
signalAll( ):唤醒所有等待该条件的线程;
4)实例代码
class Demo {
* Lock lock = new ReentrantLock();
* Condition condition = lock.newCondition();
* public void method1(){
* lock.lock();
* try{
* while()
* condition.await();
* statements;
* }catch(InterruptedException ex){
* }finally{
* lock.unlock();
* }
* }
* public void method2(){
* lock.lock();
* try{
* statements;
* condition.signalAll();
* }finally{
* lock.unlock();
* }
* }
* }/*method1在条件不满时线程被挂起,对象锁释放,
method2获取对象锁之后,进行相应的操作修改条件,并释放对象锁
method1再次获取对象锁后,满足条件并执行之后的代码;*/
实例:仿真延时多输线程输入开关(响应每一个任务):
class Switch{ Lock lock = new ReentrantLock(); Condition condition = lock.newCondition(); private boolean switch; public void turnOn(){ lock.lock(); try{ while(switch == true) condition.await(); TimeUnit.SECONDS.sleep(2); switch = true; condition.signalAll(); }catch(InterruptException e){ }finally{ lock.unlock(); } } public void turnOff(){ lock.lock(); try{ while(switch == false) condition.await(); switch = false; condition.signalAll(); }catch(InterruptException e){ }finally{ lock.unlock(); } } }
4、阻塞队列BlockingQueue<T>
1)wait和notifyAll是以一种比较底层的方式解决任务互操作的问题,可以使用java.util.concurrent.BlockingQueue同步队列这种更高抽象级别的方式来解决这样的问题;
2)BlockingQueue在任何时刻都只允许一个任务加入或删除元素时,即能维持线程同步,BlockingQueue为线程安全的;
3)BlockingQueue的主要实现具体类:
①ArrayBlockingQueue:有界阻塞队列,当满队时,加入操作的任务会被阻塞,但队空时,删除操作的任务会被阻塞;
②LinkedBlockingQueue:无界阻塞队列;
4)BlockingQueue很适合用来实现生产者-消费者模型;
5)实例
//生产者-消费者模型public class Producer implements Runnable{ BlockingQueue<String> queue; public Producer(queue){ this.queue = queue;} public void run(){ try{ <statements to product> String produce = ....; queue.put(produce); }catch(InterruptedException e){ <statements while task is blocked> } }}public class Consumer implements Runnable{ BlockingQueue<String> queue; public Consumer(BlockingQueue<String> queue){ this.queue = queue} public void run(){ try{ String produce = queue.take(); <statements to use produce> }catch(InterruptException e){ <statements whlie the task is blocked> } }}public class Test{ public static void main(){ ExecuteService exec = Executors.newCachedThradPool(); BlockingQueue<String> queue = new LinkedBlockingQueue(); exec.execute(new Producer(queue)); exec.execute(new Consumer(queue)); exec.execute(new Consumer(queue)); exec.shutdown(); }}
5、任务间使用管道进行输入/输出
1)在Java中PipedWriter、PipedReader类库提供线程功能以“管道”的形式对线程间的输入/输出提供了支持;
PipedWriter:允许不同任务任务向管道写入;
PipedReader:允许不同任务从同一个管道读取;
2)示例代码:
import java,io.*;class Sender implementouts Runnable{ private PipedWriter out = new PipedWriter(); public void run(){ while(true){ out.write('A'+new Random().nextInt(26)); }catch(IOException e){ }catch(InterruptedException e){ } }}class Receiver implements Runnable{ private PipedReader in = new PipedReader(); private static count; public void run(){ while(true){ char get = (char)in.read(); System.out.println("Receiver "+ count++ +" Read:"+ get); }catch(IOException e){ }catch(InterrupedException e){ } }}class Test{ public static void main(){ ExecutorServcie exec = Executors.newCachedThreadPool(); exec.execute(new Sender()); exec.execute(new Revicer()); exec.execute(new Revicer()); TimeUnit.SECONDS.sleep(20); exec.shutdownNow(); }}
0 0
- JAVA线程间的通信
- java线程间的通信
- Java 线程间的通信
- java间的线程通信
- java线程间的通信
- Java线程间的通信
- java线程间的通信
- java的线程通信
- JAVA线程-线程间通信
- Java的多线程-线程间的通信
- java 线程间通信
- java线程间通信
- Java线程间通信
- java线程间通信
- Java-线程间通信
- java线程间通信
- Java线程间通信
- java线程间通信
- Android--点击视图外部,隐藏键盘
- laravel框架 composer安装 及简单的增、删、改、查(分页)
- flash摄像头的使用
- Python自学之计算
- Linux下C语言学习之路——(0)学习路线的选择
- Java线程间的通信
- 两张图片相似度比较
- Python自学之String
- Pojo
- 在navicat for mysql中建立触发器
- 观察者模式
- 在lua中常用到的几个小函数
- Python自学之collection
- 帧速度的控制