线程生产者与消费者——盒子中存取苹果

阅读: 评论:0

线程生产者与消费者——盒子中存取苹果

线程生产者与消费者——盒子中存取苹果

线程知识:

synchronized

synchronized 用在方法签名上(以test为例),当某个线程调用此方法时,会获取该实例的对象锁,方法未结束之前,其他线程只能去等待。当这个方法执行完时,才会释放对象锁。其他线程才有机会去抢占这把锁,去执行方法test,但是发生这一切的基础应当是所有线程使用的同一个对象实例,才能实现互斥的现象。否则synchronized关键字将失去意义。
使用synchronized代码块,可以只对需要同步的代码进行同步,这样可以大大的提高效率。

synchronized(obj){
//todo code here
}

wait()

释放占有的对象锁,线程进入等待池,释放cpu,而其他正在等待的线程即可抢占此锁,获得锁的线程即可运行程序。

sleep()

线程调用此方法后,会休眠一段时间,休眠期间,会暂时释放cpu,但并不释放对象锁。也就是说,在休眠期间,其他线程依然无法进入此代码内部。休眠结束,线程重新获得cpu,执行代码。

notify()

该方法会唤醒因为调用对象的wait()而等待的线程,其实就是对对象锁的唤醒,从而使得wait()的线程可以有机会获取对象锁。调用notify()后,并不会立即释放锁,而是继续执行当前代码,直到synchronized中的代码全部执行完毕,才会释放对象锁。

notifyAll()

唤醒所有等待的线程。
wait() 与notify()/notifyAll()都是Object的方法,并不是线程的方法!

关键问题

Runnable定义的子类中没有start()方法,只有Thread类中才有。
在程序开发中只要是多线程肯定永远以实现Runnable接口为主,因为实现Runnable接口相比继承Thread类有如下好处:
避免点继承的局限,一个类可以继承多个接口。

先明白两个概念:锁池和等待池。synchronized是锁池,wait、notify、notifyAll是等待池。等待池的对象是不会竞争锁的,当notifyAll后,等待池中的线程会被唤醒进入到该线程的锁池中重新竞争对象锁,重新获得锁后的对象会从wait后继续执行代码,其他对象会被阻塞,而不是wait。被阻塞的对象会等待下一次被唤醒(notify、notifyAll)。另外,notify不是线程安全的,notifyAll才是。

适合于资源的共享

题目

生产者:向盒子里放苹果
消费者:从盒子里取苹果
盒子:苹果数量不超过5

这个问题用线程来实现

先建立一个苹果类
给生成的苹果一个编号

public class Apple {//苹果编号int id;public Apple(int id) {this.id = id;}
}

盒子

public class Box {//装苹果的盒子 为什么是链表 因为 它有veFirst();方法 方便取出苹果public LinkedList<Apple> boxs =new LinkedList<Apple>();public List<Apple> getBoxs() {return boxs;}public void setBoxs(LinkedList<Apple> boxs) {this.boxs = boxs;}public synchronized void push(Apple apple,String threadName){//盒子容量5while (boxs.size()==5){try {System.out.println(threadName+":盒子满了,放不下(进入等待状态),快叫消费者来消费");this.wait();} catch (InterruptedException e) {e.printStackTrace();}}//唤醒所有等待线程 notifyAll();安全  ---notify()不安全ifyAll();//苹果放进盒子中System.out.println(threadName+"生产苹果"+apple.id);boxs.add(apple);try {//线程等待0.5秒便于观察Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}public synchronized void  pop(String threadName){while (boxs.size()==0){try {System.out.println(threadName+":盒子没苹果了(进入等待状态),快叫生产者来生产");this.wait();} catch (InterruptedException e) {e.printStackTrace();}}//唤醒所有等待线程 notifyAll();安全  ---notify()不安全ifyAll();//盒子中拿去第一个苹果System.out.println(threadName+"消费苹果");veFirst();try {//线程等待0.5秒便于观察Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}
}

消费者

public class Consumer implements Runnable {Box box=null;public Consumer(Box box) {this.box = box;}@Overridepublic void run() {while (true) {//互斥synchronized (Consumer.class) {box.pop(Thread.currentThread().getName());}}}
}

生产者

public class Producer  implements  Runnable{public static Integer count = 0;Box box = null;public Producer(Box box) {this.box = box;}public void run() {while (true) {synchronized (Producer.class) {count++;//生产者给苹果编号Apple apple =new Apple(count);box.push(apple,Thread.currentThread().getName());}}}}

测试类

public class AppleThreadTest {public static void main(String[] args) {//盒子Box box =new Box();//生产者Producer p1=new Producer(box);Producer p2=new Producer(box);//消费者Consumer c1 =new Consumer(box);Consumer c2 =new Consumer(box);//创建线程Thread t1=new Thread(p1,"生产者——小刘");Thread t2=new Thread(p2,"生产者——小李");Thread t3=new Thread(c1,"消费者——老刘");Thread t4=new Thread(c2,"消费者——老李");//启动线程t1.start();t2.start();t3.start();t4.start();}
}

运行结果:

我们发现都是盒子里没苹果了,为什么呢?
因为一共4个线程2个生产者2个消费者,优先级都一样 加减基本维持在0
我们可以改变其中一个的优先级
c2.setPriority(10);
java 中的线程优先级的范围是1~10,默认的优先级是5。

本文发布于:2024-02-04 12:54:26,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170707725155761.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:生产者   线程   盒子   消费者   苹果
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23