JUC详解 -> 生产者消费者问题
面试必问:单例模式、排序算法、生产者消费者问题、死锁
1. Synchronized版生产者消费者问题
/**
* 线程之间的通信问题:生产者和消费者问题!
* 线程交替执行
* 线程A、B 操作同一个变量 +1/-1
* 等待唤醒、通知唤醒
*/
public class Demo01 {
public static void main(String[] args) {
Data data = new Data();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
}
}
//判断等待-->业务-->通知
//资源类
class Data{
private int number = 0;
//+1
public synchronized void increment() throws InterruptedException {
if(number != 0){
//等待
this.wait();
}
number++;
System.out.println(Thread.currentThread().getName()+"=>"+number);
//通知其他线程+1完毕
this.notifyAll();
}
//-1
public synchronized void decrement() throws InterruptedException {
if(number == 0){
//等待
this.wait();
}
number--;
System.out.println(Thread.currentThread().getName()+"=>"+number);
//通知其他线程-1完毕
this.notifyAll();
}
}
存在的问题:假如有4个线程,就不安全了!if -->虚假唤醒问题!
if改为while 防止虚假唤醒
public class Demo01 {
public static void main(String[] args) {
Data data = new Data();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"D").start();
}
}
//判断等待-->业务-->通知
//资源类
class Data{
private int number = 0;
//+1
public synchronized void increment() throws InterruptedException {
//while判断防止虚假唤醒
while(number != 0){
//等待
this.wait();
}
number++;
System.out.println(Thread.currentThread().getName()+"=>"+number);
//通知其他线程+1完毕
this.notifyAll();
}
//-1
public synchronized void decrement() throws InterruptedException {
while(number == 0){
//等待
this.wait();
}
number--;
System.out.println(Thread.currentThread().getName()+"=>"+number);
//通知其他线程-1完毕
this.notifyAll();
}
}
2. JUC版生产者消费者问题
- 通过Lock找到Condition
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Demo02 {
public static void main(String[] args) {
Resources resources = new Resources();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
resources.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
resources.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
resources.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
resources.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"D").start();
}
}
class Resources{
private int num = 0;
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
public void increment() throws InterruptedException {
try{
lock.lock();
while(num != 0){
condition.await(); //等待
}
num ++;
System.out.println(Thread.currentThread().getName()+"=>"+num);
condition.signalAll(); //唤醒全部
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void decrement() throws InterruptedException {
try{
lock.lock();
while(num == 0){
condition.await();
}
num--;
System.out.println(Thread.currentThread().getName()+"=>"+num);
condition.signalAll();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
问题:线程是随机执行的状态!如何有序执行A->B->C->D?
Condition的优势在哪里?
任何一个新的技术,绝不是仅仅覆盖了原来的技术,一定有其优势和补充!
Condition 可以精准通知和唤醒线程!
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author Anobabe
* A 执行完调用B,B执行完调用C,C执行完调用A
*/
public class Demo03 {
public static void main(String[] args) {
Data2 data2 = new Data2();
new Thread(()->{
for (int i = 0; i < 10; i++) {
data2.printA();
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
data2.printB();
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
data2.printC();
}
},"C").start();
}
}
class Data2{
private Lock lock = new ReentrantLock();
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition();
private int number = 1; //1 -> A ; 2->B; 3->C
public void printA(){
lock.lock();
try{
//业务代码:判断等待->执行->通知
while(number!=1){
condition1.await();
}
System.out.println(Thread.currentThread().getName()+"=>A");
//唤醒:唤醒指定的 B
number = 2;
condition2.signal();
}catch(Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void printB(){
lock.lock();
try{
//业务代码:判断等待->执行->通知
while(number!=2){
condition2.await();
}
System.out.println(Thread.currentThread().getName()+"=>B");
number = 3;
condition3.signal();
}catch(Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void printC(){
lock.lock();
try{
//业务代码:判断等待->执行->通知
while(number!=3){
condition3.await();
}
System.out.println(Thread.currentThread().getName()+"=>C");
number = 1;
condition1.signal();
}catch(Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}