概述
在中国并发这个词已经非常常见了,比如双十一购物狂欢节的淘宝,过年回家的春运12306,这都是我们生活中的并发。在短时间内大量集中的访问一个服务器。然而Java又是解决并发的一把好手,下面简单介绍一下多线程案例的经典案例,生产者和消费者
。
多线程通信图解
如何编写一个多线程配合的代码
- 线程操作资源类。定义一个资源类,并在资源类中完成相应的方法,将资源类作为成员变量传递进线程中进行操作。
- 如何编写资源类中的方法,判断,干活,通知。先判断现在是不是该我干活了,如果是那么我就干活,干完活则通知另外一位工作者来干活。
生产者消费者案例三种实现方式
- 同步方法实现
- 同步代码块实现
- 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();
}
}
注意事项
- 在前两种方式中
wait
和notify
和notifyAll
方法必须写在同步代码块中。 - 在判断是否工作时最好使用
while
进行判断,防止线程的虚假唤醒。 - 在前两种方式中,唤醒都是随机唤醒的,而在第三中方式中唤醒的带有准确性唤醒的,一对一唤醒,不存在随机性。
代码写完,小弟知识浅薄,各路大神如果看出问题,可以帮我指正,我及时修改!!!