JAVA线程---线程之间的协作
2016-03-10 09:43
567 查看
java线程第三章,主要介绍线程之间的协作,我们进行多线程,肯定需要线程之间的协作,什么时候挂起,什么时候等待,如何进行上面的操作,以及操作的时机控制,首先先简单介绍一些基本的,后期通过项目中的实际操作,继续更新。
协作解决的具体问题:
当多线程(任务)进行协作时,关键是任务之间的通信,如何握手。这里仍然可以使用基础特性:互斥。互斥可以确保只有一个任务可以响应某种信号,这样就解决了资源冲突的问题,此外我们还需要为任务提供一种等待机制,可以在某个时候将自身挂起,等到外界的条件到了可以执行的时候,再让这个任务继续开动。比如盖房子的打地基,铺水泥和上钢筋,我们可以先同时进行打地基和铺水泥中的生成水泥任务,当生成水泥的任务完成时,由于地基没有完成,此时可以将铺水泥任务挂起,知道收到地基完成的信号,此时再继续进行铺水泥任务。
Java提供的方法:1)object 的 wait 和 notify
2)并发库的await和signal的Condition对象
1,wait和notify
Wait:等待某个条件发生变化,通常该条件的变化有其他任务执行使其发生变化。
1)调用wait方法时,与sleep和yield不同,已将所释放。直到某个条件发生变化,调用notify或notifyall去唤醒该任务,它才会去尝试取得锁,执行任务。并不会立刻执行
2)调用wait方法的线程,要不传入等待时间,否者只能通过notify或notifyall去唤醒
3)实现时,必须放在同步块里和同步方法中,否则在运行中或报错。
wait和notify都是object的方法
4)通常的实现方式,一般放在while里面。
具体实例:
资源的封装类:
不同任务的Runnable实现类:
测试是否正常运行,打印相关的信息:
2,错失的信号:
原因:当两个线程使用notify()和notify()进行协作时,有时会错过某个信号。
解决方案,对控制的唤醒条件进行同步锁,防止错位访问
错误代码code:
T1:
T2:
执行过程中T1已将条件进行变化,符合T2执行的条件,但由于T2可能在这之前已进入while循环里面,导致进入等待状态,错失信号。
解决方法,修改T2部分代码
T2:
3,notify和notifyAll
1)使用notifyall比使用notify更安全
2)使用notify是对notifyall的优化,因为使用notify只会唤醒一个任务。在使用过程中,必须保证被唤醒的任务是恰当的任务。因此使用notiy必须满足一下条件,缺一不可
① 所有任务等待的条件相同
②当条件发生变化时,只能有一个任务受益
③对所有存在的子类都起作用。,
不满足以上条件,只能使用notifyall,它只会唤醒等待这个锁的任务,而不是所有的任务
4,生产者和消费者模式:
1)基本模式:customModel包
5,生产者和消费者队列
标准库提供的接口:java.util.concurrent.BlockingQueue
具体:LinkedBlockingQueue
ArrayBlockingQueue
代码这里就不贴了,所有代码在这里都可以找到 这里写链接内容
协作解决的具体问题:
当多线程(任务)进行协作时,关键是任务之间的通信,如何握手。这里仍然可以使用基础特性:互斥。互斥可以确保只有一个任务可以响应某种信号,这样就解决了资源冲突的问题,此外我们还需要为任务提供一种等待机制,可以在某个时候将自身挂起,等到外界的条件到了可以执行的时候,再让这个任务继续开动。比如盖房子的打地基,铺水泥和上钢筋,我们可以先同时进行打地基和铺水泥中的生成水泥任务,当生成水泥的任务完成时,由于地基没有完成,此时可以将铺水泥任务挂起,知道收到地基完成的信号,此时再继续进行铺水泥任务。
Java提供的方法:1)object 的 wait 和 notify
2)并发库的await和signal的Condition对象
1,wait和notify
Wait:等待某个条件发生变化,通常该条件的变化有其他任务执行使其发生变化。
1)调用wait方法时,与sleep和yield不同,已将所释放。直到某个条件发生变化,调用notify或notifyall去唤醒该任务,它才会去尝试取得锁,执行任务。并不会立刻执行
2)调用wait方法的线程,要不传入等待时间,否者只能通过notify或notifyall去唤醒
3)实现时,必须放在同步块里和同步方法中,否则在运行中或报错。
wait和notify都是object的方法
4)通常的实现方式,一般放在while里面。
具体实例:
资源的封装类:
package thridOperate.operate; import Util.PrintUtil; import java.util.concurrent.TimeUnit; /**一个汽车封装类,模拟汽车的某个操作,前后具有依赖关系 * Created by acer on 2016/2/29. */ public class Car { private boolean chckeon = false; /** * 冲水操作 * * @author sn * @date 2016/2/29 11:15 */ public synchronized void wateron() { chckeon = true; //wait for dry //PrintUtil.printb("Car is watering"); notifyAll(); } /** * 擦水操作 * @author sn * @date 2016/2/29 11:17 */ public synchronized void drycar() { if (chckeon) { try { TimeUnit.MILLISECONDS.sleep(5); //模拟具体的过程 //PrintUtil.printb("Car is drying"); } catch (InterruptedException e) { e.printStackTrace(); } chckeon = false; notifyAll(); } } /** * 等待冲水 * * @author sn * @date 2016/2/29 11:17 */ public synchronized void waitforWater() { while (!chckeon) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //PrintUtil.printb("wari for watering the car"); } /** * 等待擦水 * * @author sn * @date 2016/2/29 11:17 */ public synchronized void watiforDry() { while (chckeon) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //PrintUtil.printb("the car is wait for drying"); } }
不同任务的Runnable实现类:
package thridOperate.operate; import Util.PrintUtil; import thridOperate.operate.Car; import java.util.concurrent.TimeUnit; /**对汽车进行干燥操作 * Created by acer on 2016/2/29. */ public class DryCar implements Runnable { private Car car; public DryCar(Car car) { this.car = car; } @Override public void run() { while (!Thread.interrupted()) { try { car.drycar(); car.waitforWater(); TimeUnit.MILLISECONDS.sleep(100); PrintUtil.priintall("dry is finish \n"); } catch (InterruptedException e) { PrintUtil.priintall("Exit via interrupt \n"); return; } } PrintUtil.priintall("Task of end"); } }
package thridOperate.operate; import Util.PrintUtil; import thridOperate.operate.Car; import java.util.concurrent.TimeUnit; /**对汽车进行冲水 * Created by acer on 2016/2/29. */ public class WaterCar implements Runnable { private Car car; public WaterCar(Car car) { this.car = car; } @Override public void run() { while (!Thread.interrupted()) { car.wateron(); car.watiforDry(); try { TimeUnit.MILLISECONDS.sleep(100); PrintUtil.priintall("Water is finish \n"); } catch (InterruptedException e) { PrintUtil.priintall("Exit via interrupt \n"); return; } } PrintUtil.priintall("Task is end"); } }
测试是否正常运行,打印相关的信息:
package thridOperate.operate; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; /** * Created by acer on 2016/2/29. */ public class TestOperate { public static void main(String args[]) throws InterruptedException { Car c = new Car(); ExecutorService service = Executors.newCachedThreadPool(); WaterCar waterCar = new WaterCar(c); DryCar dryCar = new DryCar(c); service.execute(waterCar); service.execute(dryCar); TimeUnit.SECONDS.sleep(5); service.shutdownNow(); } }
2,错失的信号:
原因:当两个线程使用notify()和notify()进行协作时,有时会错过某个信号。
解决方案,对控制的唤醒条件进行同步锁,防止错位访问
错误代码code:
T1:
synchronized(shareMonitor) { <set codition for T2> shareMonitor.notify(); }
T2:
While(someConditon) { synchronized(shareMonitor){ wait(); } }
执行过程中T1已将条件进行变化,符合T2执行的条件,但由于T2可能在这之前已进入while循环里面,导致进入等待状态,错失信号。
解决方法,修改T2部分代码
T2:
synchronized(shareMonitor){ While(someConditon) { wait(); } }
3,notify和notifyAll
1)使用notifyall比使用notify更安全
2)使用notify是对notifyall的优化,因为使用notify只会唤醒一个任务。在使用过程中,必须保证被唤醒的任务是恰当的任务。因此使用notiy必须满足一下条件,缺一不可
① 所有任务等待的条件相同
②当条件发生变化时,只能有一个任务受益
③对所有存在的子类都起作用。,
不满足以上条件,只能使用notifyall,它只会唤醒等待这个锁的任务,而不是所有的任务
4,生产者和消费者模式:
1)基本模式:customModel包
5,生产者和消费者队列
标准库提供的接口:java.util.concurrent.BlockingQueue
具体:LinkedBlockingQueue
ArrayBlockingQueue
代码这里就不贴了,所有代码在这里都可以找到 这里写链接内容
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- Python3写爬虫(四)多线程实现数据爬取
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序