Java多线程案例生产者消费者

概述

在中国并发这个词已经非常常见了,比如双十一购物狂欢节的淘宝,过年回家的春运12306,这都是我们生活中的并发。在短时间内大量集中的访问一个服务器。然而Java又是解决并发的一把好手,下面简单介绍一下多线程案例的经典案例,生产者和消费者

多线程通信图解

多线程通信图解

如何编写一个多线程配合的代码

  1. 线程操作资源类。定义一个资源类,并在资源类中完成相应的方法,将资源类作为成员变量传递进线程中进行操作。
  2. 如何编写资源类中的方法,判断,干活,通知。先判断现在是不是该我干活了,如果是那么我就干活,干完活则通知另外一位工作者来干活。

生产者消费者案例三种实现方式

  • 同步方法实现
  • 同步代码块实现
  • lock锁实现

代码实现一:synchronized方法

/**
* 描述资源类
*/
public class factory {

	/**用来判断是否需要生产的标志,同时模拟资源*/
	private int repertory = 0;

	/**
	* 工厂的生产方法
	*/
	public synchronized void product() {
	
		// 判断是否需要生产,如果不需要生产则进入等待状态
		while(repertory != 0) {
			try{
				this.wait();
			} catch(InterruptedException e) {
				e.printStackTrace();
			}
		}
		repertory++;
		System.out.println(Thread.currentThread().getName() + "生产," + "目前库存:" + repertory);
		// 唤醒消费者
		this.notifyAll();
	}

	public synchronized void consumer() {
		
		// 判断是否可以消费,如果不可以消费,则进入wait状态
		while(repertory == 0) {
			try{
				this.wait();
			} catch(InterruptedException e) {
				e.printStackTrace();
			}
		}

		repertory--;
		System.out.println(Thread.currentThread().getName() + "消费," + "目前库存:" + repertory);
		// 唤醒生产者
		this.notifyAll();
	}
}

代码实现二:synchronized代码块

public class Factory {

	/**用来判断是否需要生产的标志,同时模拟资源*/
	private int repertory = 0;

	/**
	* 生产方法
	*/
	public void product() {
		synchronized(this) {
		
			// 判断是否需要生产,如果不需要生产则进入等待状态
			while(repertory != 0) {
				try{
					this.wait();
				} catch(InterruptedException e) {
					e.printStackTrace();
				}
			}
			repertory++;
			System.out.println(Thread.currentThread().getName() + "生产," + "目前库存:" + repertory);
			// 唤醒消费者
			this.notifyAll();
		}
	}
	
	public void consumer() {
		synchronized(this) {
			while(repertory == 0) {
				try{
					this.wait();
				} catch(InterruptedException e) {
					e.printStackTrace();
				}
			}
			repertory--;
			System.out.println(Thread.currentThread().getName() + "消费," + "目前库存:" + repertory);
			// 唤醒生产者
			this.notifyAll();
		}
	}
}

代码实现三:lock锁

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Factory {

	/**用来判断是否需要生产的标志,同时模拟资源*/
	private int repertory == 0;
	
	/**定义锁*/
	private final Lock lock = new ReetrantLock();

	/**控制生产方法运行*/
	private final Condition product = lock.newCondition();

	/**控制消费方法运行*/
	private final Condition consumer = lock.newCondition();

	public void product() {
		lock.lock();
		try{
			// 判断是否需要生产,如果不需要生产则停止生产
			while(repertory != 0) {
				try{
					product.await();
				} catch(InterruptedException e) {
					e.printStackTrace();
				}
			}
			repertory++;
			System.out.println(Thread.currentThread().getName() + "生产," + "目前库存:" + repertory);
			// 唤醒消费者
			consumer.signal();
			
		} finally{
			lock.unlock();
		}
	}

	public void consumer() {
		lock.lock();
		try{
			while(repertory == 0) {
				try{
					consumer.await();
				} catch(interruptedException e) {
					e.printStackTrace();
				}
			}
			repertory--;
			System.out.println(Thread.currentThread().getName() + "消费," + "目前库存:" + repertory);
			// 唤醒生产者
			product.signal();
		} finally {
			lock.unlock();
		}
		
	}
}

测试类

public class Demo {

	public static void main(String[] args) {
		Factory goods = new Factory ();
		new Thread(() -> {
			for (int i = 0; i < 100; i++) {
				try {
					TimeUnit.SECONDS.sleep(1);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				goods.product3();
			}
		}, "生产者1").start();
		
		new Thread(() -> {
			for (int i = 0; i < 100; i++) {
				try {
					TimeUnit.SECONDS.sleep(1);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				goods.consumer3();
			}
		}, "消费者1").start();
		
		new Thread(() -> {
			for (int i = 0; i < 100; i++) {
				try {
					TimeUnit.SECONDS.sleep(1);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				goods.product3();
			}
		}, "生产者2").start();
		
		new Thread(() -> {
			for (int i = 0; i < 100; i++) {
				try {
					TimeUnit.SECONDS.sleep(1);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				goods.consumer3();
			}
		}, "消费者2").start();
	}
}

注意事项

  1. 在前两种方式中waitnotifynotifyAll方法必须写在同步代码块中。
  2. 在判断是否工作时最好使用while进行判断,防止线程的虚假唤醒。
  3. 在前两种方式中,唤醒都是随机唤醒的,而在第三中方式中唤醒的带有准确性唤醒的,一对一唤醒,不存在随机性。

代码写完,小弟知识浅薄,各路大神如果看出问题,可以帮我指正,我及时修改!!!

发布了11 篇原创文章 · 获赞 12 · 访问量 2863

猜你喜欢

转载自blog.csdn.net/justLym/article/details/104640047