Java多线程随笔(4):线程通信

本文介绍了Java中解决生产者消费者问题的两种方法:管程法和信号灯法,并给出了示例代码。同时,阐述了线程池的作用,如减少线程创建销毁、提高响应时间和资源利用率,并展示了ExecutorService和Executors的使用示例。
摘要由CSDN通过智能技术生成

生产者消费者问题

生产者消费者问题是在一个系统中,存在生产者和消费者两种角色,他们通过内存缓冲区进行通信,生产者生产消费者需要的资料,消费者把资料做成产品。synchronized只能实现线程同步,无法实现线程通信。

Java的Object基类就提供了几个方法解决线程通信问题:
在这里插入图片描述

注意:只能在同步方法或者同步块中使用

解决方法

1. 管程法
import java.util.LinkedList;
import java.util.Queue;

public class TestPC {
    public static void main(String[] args) {
        SynContainer container = new SynContainer();

        new Thread(new Provider(container)).start();
        new Thread(new Consumer(container)).start();
    }
}

//生产者
class Provider implements Runnable{
    SynContainer container = new SynContainer();

    public Provider(SynContainer container) {
        this.container = container;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("生产的第"+i);
            container.provide(new Item(i));
            System.out.println("生产的现容器中的第"+container.queue.size());
        }
    }
}

//消费者
class Consumer implements Runnable{
    SynContainer container = new SynContainer();

    public Consumer(SynContainer container) {
        this.container = container;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("消费的第"+container.consume().id);
            container.provide(new Item(i));
            System.out.println("消费的现容器中的第"+container.queue.size());
        }
    }
}

//生产的物品
class Item{
    int id;

    public Item(int id) {
        this.id = id;
    }
}

//中间容器
class SynContainer{
    Queue<Item> queue = new LinkedList<Item>();
    int count = 0;

    public synchronized void provide(Item item) {
        if(count == 10){
            //通知消费者,生产者等待
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        queue.add(item);
        count++;

        //唤醒
        this.notifyAll();
    }

    public synchronized Item consume() {
        if(count == 0){
            //通知生产者,消费者等待\
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        Item i = queue.poll();
        count--;

        this.notifyAll();
        return i;
    }
}
2. 信号灯法
//信号灯方法,通过标志位解决
public class TestPC2 {
    public static void main(String[] args) {
        Program program = new Program();
        new Thread(new Actor(program)).start();
        new Thread(new Audience(program)).start();
    }
}

//生产者:演员
class Actor implements Runnable{
    Program program;

    public Actor(Program program){
        this.program = program;
    }

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
//            System.out.println("正在录制节目"+i);
            program.play("abc");
        }
    }
}

//消费者:观众
class Audience implements Runnable{
    Program program;

    public Audience(Program program) {
        this.program = program;
    }

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
//            System.out.println("正在观看节目"+i);
            program.watch("abc");
        }
    }
}

//产品:节目
class Program{
    //演员表演,观众等待:true
    //观众观看,演员等待:false
    String drama; //表演的剧
    boolean flag = true;

    //表演
    public synchronized void play(String drama){
        if(!flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("演员录制了" + drama);
        //通知观众观看
        this.notifyAll();
        this.drama = drama;
        this.flag = !this.flag;
    }

    //观看
    public synchronized void watch(String drama){
        if(flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("观众观看了" + drama);
        //通知演员表演
        this.notifyAll();
        this.flag = !this.flag;
    }
}

线程池

作用:
减少了创建和销毁线程的次数,提高响应时间
重复利用线程池中的线程,降低资源消耗
便于线程管理

JDK5.0起提供了线程池相关的API:ExecutorService和Executors;
在这里插入图片描述
ExcutorService:真正的线程类接口;
Excutors:工具类,线程工厂类,用于创建并返回不同类型的线程池;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

//测试线程池
public class TestThreadPool {

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

        //将Thread放进线程池并启动
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值