【学习记录】线程学习(二):解决生产者消费者问题方法

本文只要是接上篇继续,上篇地址:
【学习记录】线程学习(一)

九、线程通信

  • wait():表示线程会一直等待,直到其他线程通知,与sleep不同,会释放锁
  • wait(long timeout):指定等待毫秒数
  • notify():唤醒一个处于等待状态的线程
  • notifyAll():唤醒同一个对象上所有调用wait()方法的线程。优先级别高的线程优先调度

以上均是Object类方法,都只能在同步方法或者同步代码块中使用,否则会抛出异常lllegalMonitorStateExcepton

经典问题:生产者、消费者问题解决办法

(1)使用管程法解决:


// ===> 使用管程法解决
public class testPC {
	
	public static void main(String[] args) {
		synContainer container = new synContainer();
		new Productor(container).start();	//生产者线程开启
		new Consumer(container).start();	//消费者线程开启
	}
}

class Productor extends Thread{
	synContainer container;
	public Productor(synContainer container) {
		this.container = container;
	}
	
	//生产:
	@Override
	public void run() {
		for (int i = 1; i < 100; i++) {
			System.out.println("生产者 ===> 生产了"+i+"只鸡");
			container.push(new Chicken(i));
		}
	}
}

class Consumer extends Thread{
	synContainer container;
	public Consumer(synContainer container) {
		this.container = container;
	}
	
	//消费
	@Override
	public void run() {
		for (int i = 1; i < 100; i++) {
			System.out.println("消费者 ===> 消费了"+container.pop().id+"只鸡");
		}
	}
}


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) {
		//如果容器满了,需要等待消费者
		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) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		//如果可以消费
		count--;
		Chicken chicken = chickens[count];
		
		//通知生产者生产
		this.notifyAll();
		return chicken;
	}	
}

(2)使用信号灯法解决:


// ===> 使用信号灯法(标志位flag)解决
public class testPC {
	public static void main(String[] args) {
		Cake cake = new Cake();
		new Producer(cake).start();
		new Consumer(cake).start();
	}
}

class Producer extends Thread{	//面包师
	
	Cake cake;
	public Producer(Cake cake) {
		this.cake = cake;
	}
	@Override
	public void run() {
		for (int i = 0; i < 20; i++) {
			this.cake.make("蛋糕");
		}
	};
}

class Consumer extends Thread{	//消费者
	Cake cake;
	public Consumer(Cake cake) {
		this.cake = cake;
	}
	
	@Override
	public void run() {
		for (int i = 0; i < 20; i++) {
			cake.eat();
		}
	};
}

class Cake{
	//面包师制作,消费者等待  True
	//消费者在吃蛋糕,面包师等待  False
	String cake;	//蛋糕
	boolean flag = true;	//标志位,这是解决的关键
	
	//制作蛋糕
	public synchronized void make(String cake) {
		//面包制作完了,面包师等待
		if (!flag) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println("面包师===>制作了"+cake);
		//通知消费者可以吃了
		this.notifyAll();
		this.cake = cake;
		this.flag = !this.flag;
		
	}
	
	//吃蛋糕
	public synchronized void eat() {
		//如果蛋糕还没制作完成,消费者就等待蛋糕制作
		if(flag) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println("消费者 ===> 吃完了"+cake);
		//消费者已经吃完了蛋糕,通知面包师制作蛋糕
		this.notifyAll();
		this.flag = !this.flag;		
	}
}

十、线程池

1、背景:

经常创建和销毁、使用量特别大的资源,比如并发情况下的线程,对性能影响很大

2、思路:

提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。
(可以避免频繁创建销毁,实现重复利用)

3、好处:
  • 提高响应速度(减少创建新线程时间)
  • 降低资源消耗(重复利用线程池中线程,不需要每次都创建)
  • 便于线程管理

corePoolSize:核心池大小

maximumPoolSize:最大线程数

keepAliveTime:线程没有任务时最多保持多长时间后会终止

4、使用:

线程池相关API:ExecutorServiceExecutors

(1)ExecutorService:

真正的线程池接口(常见子类ThreadPoolExecutor)

//执行任务/命令,没有返回值,一般用来执行Runnable
void execute(Runnable command) 

//执行任务,有返回值,一般用来执行Callable
<T> Future<T> submit(Callable<T> task)
 
//关闭连接池
void shutdown()	

//创建线程池例子
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class testPool {
	
	public static void main(String[] args) {
		
		//创建服务,创建线程池
		//newFixedThreadPool:参数为线程池大小
		ExecutorService service = Executors.newFixedThreadPool(10);
		
		//执行
		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());	
	}
}

(2)Executors:

工具类、线程池的工厂类,用于创建并返回不同类型的线程池

tip: 线程开启不一定立即执行,由CPU调度执行


本文笔记主要来源:【狂神说Java】多线程详解

你可能感兴趣的:(java)