#Java多线程03

线程协作

生产者消费者模式

某个模块负责产生数据,这些数据由另一个模块来负责处理(此处的模块是广义的,可以是类、函数、线程、进程等)。产生数据的模块,就形象地称为生产者;而处理数据的模块,就称为消费者。

这就是一个线程同步的问题了,生产者和消费者之间共用同一个资源,并且生产者和消费者之间相互依赖,此时光用synchronized是无法解决这个问题,因为它无法实现线程之间的通信,所以要引入新的方法


sleep不会释放锁,wait会释放锁

解决方法1--管程法

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

        new Producer(container).start();
        new Consumer(container).start();
    }

}

//生产者
class Producer extends Thread{
    SynContainer container;

    public Producer(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++) {
            container.pop();//先判断有无鸡可以消费
            System.out.println("消费了--->" + container.pop().id + "只鸡");//pop方法返回chicken对象,chicken对象里有id属性
        }
    }
}

//产品
class Chicken{
    //产品编号
    int id;
    public Chicken(int id) {
        this.id = id;
    }
}


//缓冲区
class SynContainer{
    //对象数组,数组的每一个元素都是一个对象的引用,此时对象数组作为容器
    Chicken[] chickens = new Chicken[10];
    //容器计数器
    int count = 0;
    //生产者放入产品
    public synchronized void push(Chicken chicken){
        //如果容器满了,叫消费者消费产品,生产者停止生产
        if(count == 10){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
        //如果容器没满,叫生产者生产产品
        chickens[count] = chicken;
        count++;
        this.notifyAll();
    }

    //消费者消费产品
    public synchronized Chicken pop(){
        //判断能否消费
        if(count == 0){
            //等待生产者生产,消费者进行等待
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        //如果可以消费
        count--;
        Chicken chicken = chickens[count];
        //吃完了,通知生产者生产
        this.notifyAll();
        return chicken;
    }
}

这里注意一定要先--,否则会有空指针或者数组下标越界的问题,好好理一下逻辑,应该是要先--的,因为生产是先++,所以消费一定是先--才能消费到同一个count的数据
感觉怪怪的,不知道哪里有问题

解决方法2--信号灯法


就是设置一个标志位flag

线程池

有了线程池,可以不用频繁的创建和销毁线程,想用哪个线程直接去线程池里取,用完放回去,提高了性能



直接上代码,其实就是多了一种启动线程的方式

public class TestPool {
    public static void main(String[] args) {
        //1.创建线程池,创建服务
        //newFixedThreadPool 参数为:线程池大小
        ExecutorService service = Executors.newFixedThreadPool(10);

        //2.启动线程
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        //之前启动线程的方式
        new Thread(new MyThread()).start();

        //3.关闭连接
        service.shutdown();
    }

}

class MyThread implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}

结果如图


补充:
1.之前启动线程是通过start()方法,现在可以通过 service.execute()来启动

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容