Java多线程06:线程通信

synchronized实现了同步,但不能实现不同线程之间的消息传递

线程通信的三种方法(只能在同步方法和同步块中使用,否则抛出异常):

wait()方法,表示线程一直等待,直到其他线程通知,与sleep()不同,wait()会释放锁

notify()方法,唤醒一个处于等待的线程

notifyAll()方法,唤醒同一个对象上所有调用wait()方法的线程,优先级高的线程优先调度

管程法

利用缓冲区

import java.util.ArrayList;

public class Main {

    public static void main(String[] args) {

        ArrayList<Integer> arrayList = new ArrayList();

        Consumer consumer = new Consumer(arrayList);
        Producer producer = new Producer(arrayList);

        /**
         * 生产消费各十次(注意不能在run()方法里循环十次,不然会生产完所有苹果再消费)
         */
        for (int i = 0; i < 10; i++) {

            new Thread(consumer).start();
            new Thread(producer).start();
        }
    }
}

/**
 * 定义消费者类
 */
class Consumer implements Runnable {

    ArrayList<Integer> arrayList;

    public Consumer(ArrayList arrayList){
        this.arrayList = arrayList;
    }

    @Override
    public void run() {

        synchronized (arrayList) {

            if (arrayList.size() == 0) {

                System.out.println("苹果没有了,需要生产");

                try {

                    /**
                     * 没有苹果时消费者进入等待,收到唤醒后才会继续执行后续的代码
                     * wait()方法让线程进入等待,释放锁给生产线程
                     */
                    arrayList.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            /**
             * 为了避免生产完立即被消费,设置一个延时
             */
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            if (arrayList.size() != 0){

                arrayList.remove(0);
                System.out.println("消费了一个苹果,还剩" + arrayList.size() + "个");
            }

            /**
             * notify()方法唤醒生产线程
             */
            arrayList.notify();
        }
    }
}

/**
 * 定义生产者类
 */
class Producer implements Runnable{

    ArrayList<Integer> arrayList;

    /**
     * 定义缓冲区的大小
     * 生产者将产品放入缓冲区,消费者从缓冲区拿出产品
     */
    int max = 10;

    public Producer(ArrayList arrayList){

        this.arrayList = arrayList;
    }

    @Override
    public void run() {

        synchronized (arrayList) {

            if (arrayList.size() == max) {

                System.out.println("盘子满了,需要消费");

                try {
                    arrayList.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            arrayList.add(1);
            System.out.println("生产了一个苹果,还剩" + arrayList.size() + "个");
            arrayList.notify();
        }
    }
}

信号灯法

利用标志位

import java.util.ArrayList;

public class Main {
    public static void main(String[] args) {

        /**
         * 不同类的对象需要操作同一个标志位
         * 因此创建一个Goods类,在其中定义标志位,然后将生产和消费的方法放在该类中去执行
         */
        ArrayList<Integer> arrayList = new ArrayList();
        Goods goods = new Goods(arrayList);

        Consumer consumer = new Consumer(goods);
        Producer producer = new Producer(goods);

        for (int i = 0; i < 10; i++) {

            new Thread(consumer).start();
            new Thread(producer).start();
        }
    }
}

class Consumer implements Runnable{

    Goods goods;

    public Consumer(Goods goods){

        this.goods = goods;
    }

    @Override
    public void run() {

        goods.consume();
    }
}

class Producer implements Runnable{

    Goods goods;

    public Producer(Goods goods){

        this.goods = goods;
    }

    @Override
    public void run() {

        goods.produce();
    }
}

class Goods {

    ArrayList<Integer> arrayList;
    boolean flag = true;

    public Goods(ArrayList<Integer> arrayList){

        this.arrayList = arrayList;
    }

    public void produce(){

        synchronized (arrayList) {

            if (!flag) {

                try {
                    arrayList.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            arrayList.add(1);
            System.out.println("生产了一个苹果,还剩" + arrayList.size() + "个");

            /**
             * 反转标志位,让消费者线程运行
             */
            flag = !flag;
            arrayList.notify();
        }
    }

    public void consume(){

        synchronized (arrayList) {

            if (flag) {

                System.out.println("苹果没有了,需要生产");

                try {
                    arrayList.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            if (arrayList.size() != 0){

                arrayList.remove(0);
                System.out.println("消费了一个苹果,还剩" + arrayList.size() + "个");
            }

            /**
             * 反转标志位,让生产者线程运行
             */
            flag = !flag;
            arrayList.notify();
        }
    }
}
posted @ 2021-09-17 19:15  振袖秋枫问红叶  阅读(35)  评论(0)    收藏  举报