线程协作(生产者消费者模式)
-
线程通信
-
应用场景:生产者和消费者问题
-
假设仓库中只能存放一件产品,生产者将生产出来的产品放入仓库,消费者将仓库中产品取走消费
-
如果仓库中没有产品,则生产者将产品放入仓库,否则停止生产并等待,直到仓库中产品被消费则取走为止
-
如果仓库中放有产品,则消费者可以将产品取走消费,否则停止消费并等待,知道仓库中再次放入产品为止
-
这是一个线程同步的问题,生产者和消费者共享一个资源,并且生产者和消费者之间相互依赖,互为条件
- 对于生产者,没有生产产品之前,要通知消费者等待,而生产了此产品之后,有需要马上通知消费者消费
- 对于消费者,在消费之后,要通知生产者已经结束消费,需要生产新的产品以供消费
- 在生产者消费者问题中,仅有synchronized是不够的
- synchronized可组织并发更新同一个共享资源,实现了同步
- synchronized不能用来实现不同线程之间的消息传递(通信)
-
java提供了几个方法解决线程之间的通信问题
解决方式1
-
并发协作模式“生产者/消费者模式”—>管程法
package Thread;
public class TestPC {
public static void main(String[] args) {
Syncontainer container = new Syncontainer();
new Productor(container).start();
new Custom(container).start();
}
}
//生产者
class Productor extends Thread{
Syncontainer container;
public Productor(Syncontainer container){
this.container=container;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("生产了"+i+"只鸡");
container.push(new Chicken(i));
}
}
}
//消费者
class Custom extends Thread{
Syncontainer container;
public Custom(Syncontainer container){
this.container=container;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("消费了"+i+"只鸡");
container.pop();
}
}
}
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){
//如果容器里有10只鸡则暂时停止生产,若不够10只则通知生产者继续生产
if (count==chickens.length){
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;
}
}
-
信号灯法
package Thread; public class TestPC2 { public static void main(String[] args) { TV tv=new TV(); new Player(tv).start(); new Watcher(tv).start(); } } class Player extends Thread{ TV tv; public Player(TV tv){ this.tv=tv; } @Override public void run() { for (int i = 0; i < 20; i++) { if (i%2==0){ this.tv.play("22222"); }else { this.tv.play("xxxxxx"); } } } } class Watcher extends Thread{ TV tv; public Watcher(TV tv){ this.tv=tv; } @Override public void run() { for (int i = 0; i < 20; i++) { tv.watch(); } } } class TV{ String voice; boolean flag=true; public synchronized void play(String voice){ if (!flag){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("演员来表演了:"+voice); this.notifyAll(); this.voice=voice; this.flag=!this.flag; } public synchronized void watch(){ if (flag){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("观看了"+voice); this.notifyAll(); this.flag=!this.flag; } }
线程池
-
背景:经常创建和销毁、使用量特别大的资源,比如并发情况下的线程,对性能影响很大。
-
思路:提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。可以避免频繁创建销毁,实现重复利用,类似生活中的公共交通工具。
-
好处:
- 提高响应速度(减少了创建新线程的时间)
- 降低资源消耗(重复利用线程池中的线程,不需要每次都创建)
- 便于线程管理(…)
- corePoolSize:核心池的大小
- maxmunPoolSize:最大线程数
- keepAliveTime:线程没有任务时最多保持多长时间后会终止
-
使用线程池
-
JDK 5.0起提供了线程池相关API:ExecutorService和Executors
-
ExecutorService:真正的线程池接口,常见子类ThreadPoolExecutor
-
void execute (Runnable command):执行任务/命令,没有返回值,一般用来执行Runnable
-
void shutdown():关闭连接池
-
Executors:工具类,线程池的工厂类,用于创建并返回不同类型的线程池。
-
package Thread; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class TestPool { public static void main(String[] args) { ExecutorService service= Executors.newFixedThreadPool(10); service.execute(new Thread1()); service.execute(new Thread1()); service.execute(new Thread1()); service.shutdown(); } } class Thread1 implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()); } }
-
wan