理解多线程,使用synchronized简单实现多生产者多消费者

区分程序,进程和线程的概念:

  • 程序:一个可执行的文件
  • 进程:一个正在运行的程序.也可以理解成在内存中开辟了一块儿空间
  • 线程:负责程序的运行,可以看做一条执行的通道或执行单元,所以我们通常将进程的工作理解成线程的工作

打个比方,程序是一家没有业务的公司,进程就是这家公司接到业务了,线程是指负责这个业务的具体实施人.
所以一个进程至少有一个线程,就像一个公司怎么着都得有一个老板.

多线程的作用:实现同一个时间干多件事情.

如果你知道操作系统的一点知识的话,你就明白事实上cpu同一个时间只能执行一个线程.
众所周知:人的眼睛一秒钟观察到24帧以上的画面就会认为是连续的.
人类的时间单位是秒,cpu的时间单位可就小多了.
进程有三种状态

分配到时间片之后,就绪态进程就可以转为运行态,时间片耗尽后,cpu分发下个时间片,所有就绪态的进程都会去抢夺时间片,抢到后进入下一个的轮回.
所以多线程会无序的执行多个任务.

为了解决在并发编程中存在的线程安全问题,我们要使用锁。关键字synchronized可以保证在同一时刻,只有一个线程可以执行某个方法或某个代码块
理解synchronized关键字
1、synchronized关键字的作用域有二种:

  • 1)是某个对象实例内,synchronized aMethod(){}可以防止多个线程同时访问这个对象
    的synchronized方法(如果一个对象有多个synchronized方法,只要一个线程访问了其中的
    一个synchronized方法,其它线程不能同时访问这个对象中任何一个synchronized方法)。
    这时,不同的对象实例的synchronized方法是不相干扰的。也就是说,其它线程照样可以同时
    访问相同类的另一个对象实例中的synchronized方法;
  • 2)是某个类的范围,synchronized static aStaticMethod{}防止多个线程同时访问
    这个类中的synchronized static 方法。它可以对类的所有对象实例起作用。

2、除了方法前用synchronized关键字,synchronized关键字还可以用于方法中的某个区块中,
表示只对这个区块的资源实行互斥访问。用法是: synchronized(this){/区块/},它的作用域是当前对象;

3、synchronized关键字是不能继承的,也就是说,基类的方法synchronized f(){}
在继承类中并不自动是synchronized f(){},而是变成了f(){}。继承类需要你显式的指定
它的某个方法为synchronized方法.

使用synchronized简单实现多生产者多消费者


//synchronized多生产者多消费者
public class ThreadTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//准备产品
		Product product = new Product("哪吒手办",100);
		//创建生产者和消费者任务
		Producer producer = new Producer(product);
		Consumer consumer = new Consumer(product);
		//创建多线程
		Thread prot0 = new Thread(producer);
		Thread prot1 = new Thread(producer);
		Thread cont2 = new Thread(consumer);
		Thread cont3 = new Thread(consumer);
		//开启多线程
		prot0.start();
		prot1.start();
		cont2.start();
		cont3.start();
	}

}
class Product{
	private String name;//产品名称
	private int num;//产品数量
	boolean flag;//标识
	
	public Product() {
		super();
		// TODO Auto-gsenerated constructor stub
	}

	public Product(String name, int num) {
		super();
		this.name = name;
		this.num = num;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getNum() {
		return num;
	}

	public void setNum(int num) {
		this.num = num;
	}
	
	//生产功能
	public synchronized void produce() {
		while(flag == true) {//单生产者单消费者while换成if即可
			try {
				wait();//生产线程进入等待
			} catch (InterruptedException e) {
				// TODO: handle exception
				e.printStackTrace();
			}
			
		}
		System.out.println(Thread.currentThread().getName()+"生产:" + name + ",库存数量:" + (num++));
		flag = !flag;
		//notify();
		notifyAll();//唤醒消费线程
	}
	//消费功能
	public synchronized void consume() {
		while(flag == false) {//单生产者单消费者while换成if即可
			try {
				wait();//消费线程进入等待
			} catch (InterruptedException e) {
				// TODO: handle exception
				e.printStackTrace();
			}
			
		}
		System.out.println(Thread.currentThread().getName()+"消费:"+name+",库存数量:"+(num--));
		flag = !flag;
		//notify();
		notifyAll();//唤醒生产线程
	}
}
class Producer implements Runnable{
	Product product;
	
	public Producer(Product product) {
		super();
		this.product = product;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		for(int i = 0; i < 100; i++) {
			product.produce();
		}
	}
	
}
class Consumer implements Runnable{
	Product product;
	
	
	public Consumer(Product product) {
		super();
		this.product = product;
	}


	@Override
	public void run() {
		// TODO Auto-generated method stub
		for(int i = 0; i < 100; i++) {
			product.consume();
		}
	}
	
}