生产者消费者问题
生产者消费者问题是在一个系统中,存在生产者和消费者两种角色,他们通过内存缓冲区进行通信,生产者生产消费者需要的资料,消费者把资料做成产品。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());
}
}