线程的生产者消费者

线程的生产者消费者

新建一个产品Person

package cn.lucky.producer;

/**
 * @author lucky
 */
public class Person {
    private String name;
    private int age;

    public void push(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public synchronized void pop() {
        System.out.println(this.name + "---" + this.age);
    }
}

新建生产者

package cn.lucky.producer;

/**
 * @author lucky
 */
public class Producer implements Runnable{
    Person p = null;

    public Producer(Person p) {
        this.p = p;
    }

    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            if(i%2==0){
                p.push("Tom",11);
            }else {
                p.push("Marry",21);
            }
        }
    }
}

新建消费者

package cn.lucky.producer;

/**
 * @author lucky
 */
public class Consumer implements Runnable{
    Person p = null;

    public Consumer(Person p) {
        this.p = p;
    }

    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            p.pop();
        }
    }
}

测试

package cn.lucky.producer;

/**
 * @author lucky
 */
public class Test {
    public static void main(String[] args) {
        Person p = new Person();
        Producer producer = new Producer(p);
        Consumer consumer = new Consumer(p);
        new Thread(new Runnable() {
            @Override
            public void run() {
                producer.run();
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                consumer.run();
            }
        }).start();
    }
}

结果

我们发现,全是Marry,跟我们预期的Tom---11,Marry---21循环不一样。

我们加个线程休眠扩大一下现象。

package cn.lucky.producer;

/**
 * @author lucky
 */
public class Person {
    private String name;
    private int age;

    public void push(String name, int age) {
        try {
            Thread.sleep(10);
            this.name = name;
            this.age = age;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void pop() {
        try {
            Thread.sleep(10);
            System.out.println(this.name + "---" + this.age);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

虽然出现了Tom---11,但是我们还是没有达到理想效果,要如何达到呢?

首先我们对生产消费加个锁

我们会发现要么全是Tom,要么全是Marry,要么一半连续出现Tom,一半连续Marry

同步锁池的概念就出现了:

同步锁池:同步锁必须选择多个线程共同的资源对象,而一个线程获得锁的时候,别的线程都在同步锁池等待获取锁;当那个线程释放同步锁了,其他线程便开始由CPU调度分配锁

这是Object类中的方法

wait():执行该方法的线程对象,释放同步锁,JVM会把该线程放到等待池中,等待其他线程唤醒该线程

notify():执行该方法的线程唤醒在等待池中等待的任意一个线程,把线程转到锁池中等待(注意锁池和等待池的区别)

notifyAll():执行该方法的线程唤醒在等待池中等待的所有线程,把线程转到锁池中等待。

注意:上述方法只能被同步监听锁对象来调用,这也是为啥wait() 和 notify()方法都在 Object 对象中,因为同步监听锁可以是任意对象,只不过必须是需要同步线程的共同对象即可,否则别的对象调用会报错:java.lang.IllegalMonitorStateException

代码如下:

package cn.lucky.producer;

/**
 * @author lucky
 */
public class Person {
    private String name;
    private int age;

    private boolean flag=true;

    public synchronized void push(String name, int age) {
        try {
            while (!flag){
                this.wait();
            }
            Thread.sleep(10);
            this.name = name;
            this.age = age;
            flag=false;
            this.notifyAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public synchronized void pop() {
        try {
            while (flag){
                this.wait();
            }
            Thread.sleep(10);
            System.out.println(this.name + "---" + this.age);
            flag=true;
            this.notifyAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

测试结果:

完结!

posted @ 2021-03-19 19:51  Lucky8991  阅读(68)  评论(0)    收藏  举报