- 阻塞队列与就绪队列
- 每一个锁对象都有一个就绪队列与一个阻塞队列。
- 就绪队列里存放的是将要获得锁的线程;
- 阻塞队列里存放的是被阻塞的线程。
如在一个线程中使用了wait()方法后,这个线程就会被阻塞,不再继续执行,然后进入阻塞队列,直到被notify唤醒,然后进入就绪队列。下面介绍wait()与notify()方法。
- 生产者与消费者模型所需要的方法
方法 | 作用 | 是否释放锁 | 状态变化 |
---|---|---|---|
wait() | 使线程停止运行 | 是 | 运行态->阻塞态 |
notify() | 唤醒一个线程 | 是 | 阻塞态->就绪态 |
notifyAll() | 唤醒所有的线程 | 是 | 阻塞态->就绪态 |
(1)wait()方法:使线程停止运行。
1)方法wait()的作用是使当前执行代码的线程进行等待,在一个线程中使用wait()方法之后,该线程立即停止执行,直到其被唤醒。
2)wait()方法是Object类的方法。
3)wait()方法只能在同步代码块或者同步方法中使用。(即是由内建锁synchronized修饰的)。
4)使用wait()方法后,该线程释放锁,进入阻塞队列。
(2)notify()方法:唤醒一个线程
1)在同步代码块或者同步方法中使用。(即是由内建锁synchronized修饰的)。
2)如果有多个线程等待,则有线程规划器随机挑选出一个呈wait状态的线程。
3)使用notify()方法是将一个线程从阻塞队列放入到就绪队列。
4)使用notify并不会立即去唤醒一个被阻塞的线程,要先执行完当前线程之后才去。
(3)notifyAll()方法
notifyAll()的使用与notify()一样,只不过notifyAll()唤醒的是所有被wait的线程。
(4)wait(),notify(),notifyAll()的使用
package www.waitandnotify;
class MyThread implements Runnable{
private boolean flag;
private Object object;
public MyThread(boolean flag, Object object) {
super();
this.flag = flag;
this.object = object;
}
public void waitMethod(){
synchronized (object){
while (true){
System.out.println("wait()方法开始"+Thread.currentThread().getName());
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("wait()方法结束"+Thread.currentThread().getName());
return;
}
}
}
public void notifyMethod(){
synchronized (object){
System.out.println("notify()方法开始"+Thread.currentThread().getName());
object.notify();
System.out.println("notify()方法结束"+Thread.currentThread().getName());
}
}
@Override
public void run() {
if (flag){
this.waitMethod();
}else {
this.notifyMethod();
}
}
}
public class Test2 {
public static void main(String[] args) throws InterruptedException {
Object object = new Object();
MyThread myThread1 = new MyThread(true,object);
MyThread myThread2 = new MyThread(false,object);
Thread t1 = new Thread(myThread1,"wait线程");
Thread t2 = new Thread(myThread2,"notiyf线程");
t1.start();
Thread.sleep(1000);
t2.start();
System.out.println("main方法结束");
}
}
- 消费者与生产者模型
- 生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队 列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从 阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。 这个阻塞队列就是用来给生产者和消费者解耦的。纵观大多数设计模式,都会找一个第三者出来进行解耦,如工厂模式的第三 者是工厂类,模板模式的第三者是模板类。
- 思想:我们想:生产者与消费者是两个独立的类,两者的联系是商品,因此还需要一个商品类,在商品类中定义连个方法,一个生产方法,一个消费方法。
- 单一生产者与消费者
缺点:只能有一个生产者只能生产一次只能消费一次。
package www.waitandnotify;
class Goods{
private String goods;
private int count;
@Override
public String toString() {
return "Goods{" +
"name='" + goods + '\'' +
", count=" + count +
'}';
}
//生产方法
public synchronized void set(String goods) throws InterruptedException {
//当库存中还有商品时,不用再生产商品,等待消费者消费
if (this.count > 0){
System.out.println("还有库存,等待消费者。。");
wait();
}
//当库存中没有商品时,开始生产商品, 生产完后告诉消费者可以消费
this.goods = goods;
this.count++;
System.out.println(toString());
notify();
}
//消费方法
public synchronized void get() throws InterruptedException {
//当库存中没有商品时,消费者开始等待,等待生产者生产商品
if (count == 0){
System.out.println("请稍等,正在生产中。。。");
wait();
}
//当库存中有商品的时候,消费者直接消费,消费完之后告诉生产者可以生产
this.count--;
System.out.println(toString());
notify();
}
}
class Producter implements Runnable{
private Goods goods;
public Producter(Goods goods) {
super();
this.goods = goods;
}
@Override
public void run() {
try {
this.goods.set("铅笔");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Customer implements Runnable{
private Goods goods;
public Customer(Goods goods) {
super();
this.goods = goods;
}
@Override
public void run() {
try {
this.goods.get();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Test4 {
public static void main(String[] args) throws InterruptedException {
Goods goods = new Goods();
Thread product = new Thread(new Producter(goods),"生产者");
Thread customer = new Thread(new Customer(goods),"消费者");
//启动生产者线程
product.start();
//启动消费者线程
customer.start();
}
}
- 多生产多消费
针对一种商品,可以有多个生产者和多个消费者。此时又多个线程,若还是使用notify唤醒线程的话,不知道唤醒的是哪个线程,这个时候就使用notifyAll。
package www.waitandnotify;
import java.util.ArrayList;
import java.util.List;
class Goods1{
private String goodsName;
private Integer count;
public synchronized void set(String goodsName) throws InterruptedException {
while (count > 0){
System.out.println("还有票,请消费。。");
wait();
}
this.count = this.count+1;
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName());
System.out.println(toString());
System.out.println("-------------------");
notifyAll();
}
public synchronized void set() throws InterruptedException {
while (count == 0){
wait();
}
this.count = this.count-1;
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName());
System.out.println(toString());
System.out.println("--------------------");
notifyAll();
}
@Override
public String toString() {
return "Goods1{" +
"goodsName='" + goodsName + '\'' +
", count=" + count +
'}';
}
}
class Producer1 implements Runnable{
private Goods goods;
public Producer1(Goods goods) {
super();
this.goods = goods;
}
@Override
public void run() {
while (true){
try {
this.goods.set("铅笔");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Custome1r implements Runnable{
private Goods goods;
public Custome1r(Goods goods) {
super();
this.goods = goods;
}
@Override
public void run() {
while (true){
try {
this.goods.get();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Test4 {
public static void main(String[] args) {
Goods goods = new Goods();
List<Thread> threads = new ArrayList<>();
for (int i = 0;i < 6;i++){
Thread threadProduct = new Thread(new Producer1(goods),("生产者"+i));
threads.add(threadProduct);
}
for (int i = 0;i < 3;i++){
Thread threadCustomer = new Thread(new Custome1r(goods),("消费者")+i);
threads.add(threadCustomer);
}
for (Thread thread:threads){
thread.start();
}
}
}