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。要设置休息时间,也是会用方法。
标签:总结,count,消费者,synchronized,生产者,线程,Day13,Chicken,多线程 From: https://www.cnblogs.com/guoyifan/p/16736373.html