JAVA multithreading-thread cooperation (producer consumer problem)

JAVA multithreading-thread collaboration

Producer consumer problem

Producer-consumer problem: This is a thread synchronization problem. Producer-consumers share the same resource, and producer-consumers rely on each other as conditions.

For the producer, the consumer must be notified to wait before the product is produced, and after the product is produced, it must be placed in the buffer area to notify the consumer to consume

For consumers, after consumption, the producer must be notified that consumption has ended and new products need to be produced for consumption

In the producer-consumer problem, synchronized alone is not enough

Synchronized achieves synchronization, but cannot be used to achieve communication between different threads


Methods to solve communication problems between threads

wait() Let threads wait until other threads notify, unlike sleep, the lock is released

wait(long timeout) specifies the number of milliseconds to wait

notify() wake up threads in waiting state

notifyAll() wakes up all waiting threads on the same object, and the one with higher priority is scheduled first

Explain that
these methods are all methods defined in the java.lang.Object class. They can only be used in synchronized methods or synchronized blocks. The caller of the method must be a synchronized code block or synchronized monitor in a synchronized method, otherwise it will appear IllegalMonitorStateException

Supplement: the similarities and differences between sleep() and wait()

Same: Once the method is executed, the current thread can enter the blocking state

different:

  • The two methods are declared in different positions. Sleep() is declared in the Thread class, and wait() is declared in the Object class.

  • The end of the blocking state is different, sleep() will end when the time is up, wait() must pass the notifyAll() method

  • The calling requirements are different, sleep() can be called in any scenario, wait() must be used in a synchronized code block or synchronized method

  • If the two methods are not used in a synchronized code block or synchronized method, sleep() will not release the lock, wait() will release the lock



Summary

Release the lock operation:

  • The synchronization code block of the current thread, the synchronization method ends
  • When the current thread encounters break and return in the synchronization code block and synchronization method knot, the code block is terminated, and the method continues to execute
  • The current thread has an unhandled Error or Execption in the synchronization code block and synchronization method knot, resulting in an abnormal end
  • Use the wait() method

Operations that will not release the lock:

  • Execute sleep(), and yield() methods

  • When a thread executes a synchronized code block, other threads call the thread's suspend() method to suspend the thread, and the thread will not release the lock (try to avoid using suspend() and resume() to control the thread)


Solution

Producer consumer problem solution 1: management method

Producer: The module responsible for producing data (may be put, object, thread, process)

Consumer: The module responsible for processing data (may be put, object, thread, process)

Buffer: Consumers cannot directly use the producer’s data, there is a buffer between them

package com.peng.demon06;

//测试:用管程法解决生产者消费者问题,利用缓冲区

//需要的对象:生产者,消费者,产品,缓冲区
public class TestPC {
    
    
    public static void main(String[] args) {
    
    
        SynContainer container = new SynContainer();

        /*创建线程
        Productor productor = new Productor(container);
        Consumer consumer = new Consumer( new Consumer);
        开启线程
        productor.start();
        consumer.start();
        可以简化为下面两行代码
        */
        new Productor(container).start();
        new Consumer(container).start();

    }
}
//生产者
class Productor extends Thread{
    
    
    SynContainer container;
    //用构造器创建容器的对象
    public Productor(SynContainer container){
    
    
        this.container=container;
    }

    //生产的方法
    @Override
    public void run() {
    
    
        for (int i = 0; i < 100; i++) {
    
    

            container.push(new Chicken(i));//把鸡放进容器
            System.out.println("生产了"+i+"只鸡");
            
        }
    }
}
//消费者
class Consumer extends Thread{
    
    
    SynContainer container;
    //用构造器创建容器的对象
    public Consumer(SynContainer container){
    
    
        this.container=container;
    }

    //消费的方法

    @Override
    public void run() {
    
    
        for (int i = 0; i < 100; i++) {
    
    
            System.out.println("消费了-->"+container.pop().id+"只鸡");

        }
    }
}
//产品
class Chicken{
    
    
    
    int id;//定义产品的编号

    public Chicken(int id) {
    
    
        this.id = id;
    }
}
//缓冲区(容器)
class SynContainer{
    
    

    //容器的大小,可以放10个产品
    Chicken[] chickens = new Chicken[10];

    //计算容器里产品的数量
    int count = 0;
    
    //生产者放入产品
    //synchronized同步方法,让线程同步
    public synchronized void push(Chicken chicken){
    
    

        //如果容器满了,就需要消费者消费,然后生产者等待
        while (count == 10){
    
    
            //生产者等待
            try {
    
    
                this.wait();
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }

        }
        //如果没有满,生产者丢入产品
        chickens[count]=chicken;//把chicken丢进chickens数组的计数器里
        count++;

        //放完通知消费者来消费
        this.notifyAll();

    }
    //消费者消费产品
    public synchronized Chicken pop(){
    
    
        //判断能否消费
       while (count==0){
    
     //如果容器为空,
            //等待生产者生产产品,消费者等待
            try {
    
    
                this.wait();
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
        //如果可以消费
        count--;
        Chicken chicken = chickens[count];//把chickens数组的计数器里的产品取出来

        //消费完了,通知生产者生产,再放到缓冲区
        this.notifyAll();
        return chicken;
        
    }
}

Insert picture description here

Producer consumer problem solution 2: signal light method

Solve by flag

package com.peng.demon06;
//测试信号灯法——通过标志位
public class TestPC2 {
    
    
    public static void main(String[] args) {
    
    
        TV tv = new TV();
        new Player(tv).start();
        new Watcher(tv).start();
    }
}
//生产者-->演员
class Player extends Thread{
    
    
    TV tv = new TV();
    public Player(TV tv){
    
    
        this.tv = tv;
    }
        @Override
        public void run() {
    
    
            for (int i = 0; i < 20; i++) {
    
    
                if (i%2==0){
    
    
                    tv.play("中餐厅");
                }else {
    
    
                    tv.play("广告");
                }

            }
        }
}

//消费者-->观众
class Watcher extends Thread {
    
    
    TV tv = new TV();
    public Watcher(TV tv) {
    
    
       this.tv = tv;
    }

    @Override
    public void run() {
    
    
        for (int i = 0; i < 20; i++) {
    
    
            tv.watch();
        }
    }
}

//产品-->节目(不需要缓冲区了)
class TV{
    
    
    //演员表演,观众等待    true
    //观众观看,演员等待    false
    String voice;//表演的节目
    boolean flag = true;//标志位

    //表演
    public synchronized void play(String voice) {
    
    
        while (flag == false) {
    
    //如果标志位为false
            try {
    
    
                this.wait();//让演员等待
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }

            //通知观众观看
            this.notifyAll();//唤醒观众
            this.voice = voice;
            System.out.println("演员表演了" + voice);
            this.flag = !this.flag;//取反
        }

    //观看
    public synchronized void watch(){
    
    
        while (flag==true) {
    
    //如果标志位为true
            try {
    
    
                this.wait();//让观众等待
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }

            //通知演员表演,唤醒等待
            this.notifyAll();
            System.out.println("观众观看了:" + voice);
            this.flag = !this.flag;//取反

        }
}

Insert picture description here

Guess you like

Origin blog.csdn.net/wpc2018/article/details/108399655