Day13 多线程的总结

Day13

多线程学习

消费者生产者问题

关键 仓库中只能存在一件商品,生产者将生产出来的产品放在仓库,消费者将仓库中的产品取走消费

所以synchronized只能解决线程同步的问题,想要解决线程之间的通信问题。

java提供了几个方法

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

notify()唤醒一个处于等待状态的线程

想要解决生产者和消费者的问题,就需要在保持同步的同时,有通信。生产者和消费者有依赖条件。

管程法

利用一个缓冲区解决生产者和消费者的问题

写了一个生产者和消费者在生产产品的例子,用一个缓冲区来进行同步

但是在写完后,会出现先消费再生产的问题

研究了一下代码后发现,两个用synchronized锁的方法在都没达到极限时,即生产者没生产满产品,所以还在生产,消费者没消费完产品,还在消费。这时的count并没有被synchronized锁住,导致两个线程同时对count进行修改,而方法synchronized锁并没完全保护到count的计数。感觉还有问题

Chicken[] chickens=new Chicken[10];
 static  int  count=0;

//生产者生产产品
public synchronized void push(Chicken chicken)
{
    //判断仓库是否有
    while (count==chickens.length)
    {
        try {
            this.wait();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
    //没满就开始生产
    chickens[count]=chicken;
    count++;

    this.notifyAll();
}
//消费者消费产品
public synchronized  Chicken pop()
{
    while (count==0)
    {
        try {
            this.wait();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
    count--;
    Chicken chicken=chickens[count];
    
    this.notifyAll();
    return chicken;
}

信号灯法

这个方法,一般是通过标志位来解决。

有了管程法的例子,信号灯法就比较好理解,以往是用count来判断是否等待或者开始进行,现在只需要一个flag标志一个生产,一个消费即可。

线程池

在使用特别多资源,在并发的线程,对性能影响很大。

思路就是 提前创建好多个线程,使用时直接获取,用完后再放进池子里。

避免频繁的创建和销毁,实现重复利用

线程池相关API ExecutorService和 Executors

ExecutorService: 真正的线程池接口 常见子类 ThreadPoolExecutor

使用Runnable的方法 void execute(Runnable) 执行命令没有返回值

Executors:是一个工具类、线程池的工厂类,用于创建并返回不同类型的线程池。

在使用线程池时,由于类命名使用了ExecutePool导致与使用的Executepool等有冲突所以一直报错。

总结

多线程这一块大致已经学完,首先是线程的创建有三种方式

第一种 继承Thread类

第二种 用Runnable接口

第三种 callable接口

期间还有安全问题,用同步方法和同步块来保证数据的安全

一种就是synchronized锁 另一种则是用lock类手动关闭和开启

在同步的基础上还要有联系通信,就需要今天所学的两种方法,管程法和信号灯法

管程法是用在生产者和消费者之间加一个缓冲块

信号灯法则是用一个标志位来判断生产者和消费者

线程池方法在学习python爬虫就有所涉及,当初为了多管齐下爬资源,当然很容易被ban IP。要设置休息时间,也是会用方法。

posted @ 2022-09-27 23:10  青山隐隐丶  阅读(19)  评论(0编辑  收藏  举报