线程间通信
线程间通信的模型有两种:共享内存和消息传递,以下方式都是基本这两种模型来实现的。
我们来基本一道面试常见的题目来分析
场景
两个线程,一个线程对当前数值加 1,另一个线程对当前数值减 1,
要求:用线程间通信
synchronized 方案
package com.java.juc.sync;
/**
* 第一步 创建资源类,定义属性和操作方法
* @author chejuan
*/
class Share{
/**
* 初始值
*/
private int number = 0;
/**
* +1的方法
*/
public synchronized void incr() throws InterruptedException {
//第二步 判断 干活 通知
//number != 0,则等待;number = 0,+1;
while( number != 0 ){
this.wait();
}
number++;
System.out.println("incr===" + Thread.currentThread().getName() + " :: " + number);
//通知其他线程
this.notifyAll();
}
/**
* -1的方法
*/
public synchronized void decr() throws InterruptedException {
//第二步 判断 干活 通知
//number != 1,则等待 ; number != 0,-1
//if( number != 1 ){
// this.wait();//在哪里睡,再哪里醒 会存在虚假唤醒的问题
// }
while( number != 1 ){
this.wait();//while循环是不管在哪里睡,都需要判断
}
number--;
System.out.println("decr===" + Thread.currentThread().getName() + " :: " + number);
//通知其他线程
this.notifyAll();
}
}
/**
* 第三步 创建多个线程,操作资源类的方法
* @author chejuan
*/
public class ThreadDemo1 {
public static void main(String[] args) {
Share share = new Share();
//创建线程
new Thread(()->{
for(int i = 0; i < 10; i++){
try {
share.incr();//+1
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"AA").start();
new Thread(()->{
for(int i = 0; i < 10; i++){
try {
share.decr();//-1
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"BB").start();
new Thread(()->{
for(int i = 0; i < 10; i++){
try {
share.incr();//+1
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"CC").start();
new Thread(()->{
for(int i = 0; i < 10; i++){
try {
share.decr();//-1
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"DD").start();
}
}
Lock 方案
package com.java.juc.lock;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 第一步 创建资源类,定义属性和操作方法
* @author chejuan
*/
class Share{
/**
* 初始值
*/
private int number = 0;
/**
* 创建可重入锁
*/
private Lock lock = new ReentrantLock();
/**
* 创建
*/
private Condition condition = lock.newCondition();
/**
* +1的方法
*/
public void incr() throws InterruptedException {
//上锁
lock.lock();
try{
//第二步 判断 干活 通知
//number != 0,则等待;number = 0,+1;
while( number != 0 ){
condition.await();
}
number++;
System.out.println("incr===" + Thread.currentThread().getName() + " :: " + number);
//通知其他线程
condition.signalAll();
} finally {
//解锁
lock.unlock();
}
}
/**
* -1的方法
*/
public void decr() throws InterruptedException {
//上锁
lock.lock();
try{
//第二步 判断 干活 通知
//number != 1,则等待 ; number != 0,-1
while( number != 1 ){
condition.await();//while循环是不管在哪里睡,都需要判断
}
number--;
System.out.println("decr===" + Thread.currentThread().getName() + " :: " + number);
//通知其他线程
condition.signalAll();
} finally {
//解锁
lock.unlock();
}
}
}
/**
* 第三步 创建多个线程,操作资源类的方法
* @author chejuan
*/
public class ThreadDemo2 {
public static void main(String[] args) {
Share share = new Share();
//创建线程
new Thread(()->{
for(int i = 0; i < 10; i++){
try {
share.incr();//+1
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"AA").start();
new Thread(()->{
for(int i = 0; i < 10; i++){
try {
share.decr();//-1
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"BB").start();
new Thread(()->{
for(int i = 0; i < 10; i++){
try {
share.incr();//+1
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"CC").start();
new Thread(()->{
for(int i = 0; i < 10; i++){
try {
share.decr();//-1
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"DD").start();
}
}