黑马程序员_多线程2
来源:互联网 发布:滨州北海大数据产业园 编辑:程序博客网 时间:2024/05/18 02:48
---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------
通过上一节的学习,对多线程有了较为全面的了解,这里记录的主要是多线程的应用,以及JDK1.5以后的变化。
一、线程间通信:假设一个储存空间有两部分,一部分储存认得姓名,另一部分储存认得性别。有两个线程,一个向该存储空间添加数据(生产者),另一个取走数据(消费者)。这里需要考虑两个问题,1),假设生产着线程刚添加完姓名,还没有添加性别,CPU就切换到消费者线程了,出现数据不同步,引起不安全因素;2),生产者放入了N个数据,消费者才取一次一次数据,或者消费者重复取N个数据,也出现了安全问题。
1,解决数据不同步的问题,将添加和取走的语句放到同一个同步锁中;
2,解决只存不取或只取不存的问题,用等待唤醒机制,wait,notify,notifyAll,
wait();让线程处于冻结状态,被wait的线程被存储到线程池中,
notify();唤醒线程池中的一个线程(任意),
notifyAll();唤醒线程池中的所有线程。
多生产者多消费者问题:
if判断标记,只有一次,会导致不该运行的线程运行了。出现了数据错误的情况。
while判断标记,解决了线程获取执行权后,是否要运行!
notify:只能唤醒一个线程,如果本方唤醒了本方,没有意义。而且while判断标记+notify会导致死锁。
notifyAll解决了本方线程一定会唤醒对方线程的问题。
package itcast;public class ProducerConsumerDemo {public static void main(String[] args) {Resource res = new Resource();Producer pro = new Producer(res);Consumer con = new Consumer(res);Thread t0 = new Thread(pro);Thread t1 = new Thread(pro);Thread t2 = new Thread(con);Thread t3 = new Thread(con);t0.start();t1.start();t2.start();t3.start();}}class Resource{String name;boolean flag = false;int count = 1;public synchronized void set(String name){while(flag)//此处要用while而不能用iftry {wait();} catch (InterruptedException e) {}this.name = name+count;count++;System.out.println(Thread.currentThread().getName()+"....生产了...."+this.name);flag = true;notifyAll();//不能用notify,以防唤醒己方生产者线程带来不安全因素}public synchronized void get(){while(!flag)try {wait();} catch (InterruptedException e) {}System.out.println(Thread.currentThread().getName()+".........消费了...."+name);flag = false;notifyAll();}}class Producer implements Runnable{private Resource res;Producer(Resource res) {this.res = res;}public void run() {while(true){res.set("烤鸭");}}}class Consumer implements Runnable{private Resource res;Consumer(Resource res) {this.res = res;}public void run() {while(true){res.get();}}}
二、JDK1.5以后的变化
我们知道,notify唤醒的线程是随机的,如上面的例子,不能确定是唤醒的消费者线程还是生产者线程,1.5以后的变化就可以解决这个问题
jdk1.5以后将同步和锁封装成了对象, 并将操作锁的隐式方式定义到了该对象中,将隐式动作变成了显示动作。
Lock接口: 出现替代了同步代码块或者同步函数。将同步的隐式锁操作变成现实锁操作。同时更为灵活。可以一个锁上加上多组监视器。
主要方法介绍:lock():获取锁;unlock():释放锁,通常需要定义finally代码块中,因为获取锁以后不管是否发生异常都要释放锁。
Condition接口:出现替代了Object中的wait notify notifyAll方法。将这些监视器方法单独进行了封装,变成Condition监视器对象。可以任意锁进行组合。
主要方法:await()相当于wait();signal()相当于notify();signalAll()相当于notifyAll();
这样我们可以再一个锁Lock上定义两个监视器Condition,分别监视生产者和消费者。更改后的代码如下:
import java.util.concurrent.locks.*;public class ProducerConsumerDemo2 {public static void main(String[] args) {Resource res = new Resource();Producer pro = new Producer(res);Consumer con = new Consumer(res);Thread t0 = new Thread(pro);Thread t1 = new Thread(pro);Thread t2 = new Thread(con);Thread t3 = new Thread(con);t0.start();t1.start();t2.start();t3.start();}}class Resource{String name;boolean flag = false;int count = 1;Lock lock = new ReentrantLock();//创建锁对象//通过已有的锁获取两组监视器,一组监视生产者,一组监视消费者Condition proCondition = lock.newCondition();Condition conCondition = lock.newCondition();public void set(String name){lock.lock();try{while(flag)//此处要用while而不能用iftry {proCondition.await();} catch (InterruptedException e) {}this.name = name+count;count++;System.out.println(Thread.currentThread().getName()+"....生产了...."+this.name);flag = true;conCondition.signal();}finally{lock.unlock();}}public void get(){lock.lock();try{while(!flag)try {conCondition.await();} catch (InterruptedException e) {}System.out.println(Thread.currentThread().getName()+".........消费了...."+name);flag = false;proCondition.signal();}finally{lock.unlock();}}}class Producer implements Runnable{private Resource res;Producer(Resource res) {this.res = res;}public void run() {while(true){res.set("烤鸭");}}}class Consumer implements Runnable{private Resource res;Consumer(Resource res) {this.res = res;}public void run() {while(true){res.get();}}}
---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------
详细请查看:http://edu.csdn.net
- 黑马程序员_多线程2
- 黑马程序员_多线程2
- 黑马程序员_多线程2
- 黑马程序员_多线程2
- 黑马程序员_多线程2
- 黑马程序员_多线程2
- 黑马程序员_多线程2
- 黑马程序员_多线程2
- 黑马程序员_多线程
- 黑马程序员_多线程
- 黑马程序员_多线程
- 黑马程序员_多线程
- 黑马程序员_多线程
- 黑马程序员_多线程
- 黑马程序员_多线程
- 黑马程序员_多线程
- 黑马程序员_多线程
- 黑马程序员_多线程
- 快速排序
- linux字符设备驱动程序的编写
- gcc中的-finput-charset和-fexec-charset开关
- 服务器magic_quotes_gpc的方法
- 三层架构与MVC
- 黑马程序员_多线程2
- C++/java算法笔试题
- 配置文件详解
- java编译过程
- 6月27日CTO俱乐部下午茶印象
- Sql SUBSTR函数
- BUAA 555 N皇后
- java异步计算Future的使用
- Triangle