线程间通信
线程间通信的模型有两种:共享内存 和 消息传递,以下方式都是基本这两种模型来实现的。
场景—两个线程,一个线程对当前数值加 1,另一个线程对当前数值减 1。要求用线程间通信
3.1 synchronized方案
使用 wait(); notify();
public class TestMain { /** ● 交替加减*/ public static void main(String[] args){ DemoClass demoClass = new DemoClass(); new Thread(() ->{ for (int i = 0; i < 5; i++) { demoClass.increment(); } }, "线程 A").start(); new Thread(() ->{ for (int i = 0; i < 5; i++) { demoClass.decrement(); } }, "线程 B").start(); }
}
class DemoClass{ //加减对象 private int number = 0; /** * 加 1 */ public synchronized void increment() { try { while (number != 0){ this.wait(); } number++; System.out.println(currentThread().getName() + "加一成功,值为:" + number); //唤醒其他的线程notifyAll(); }catch (Exception e){ e.printStackTrace(); } } /** * 减一 */ public synchronized void decrement(){ try { while (number != 1){ this.wait(); } number--; System.out.println(currentThread().getName() + "减一成功,值为:" + number); notifyAll(); }catch (Exception e){ e.printStackTrace(); } }
}
3.2 Lock 方案
使用 Condition condition.await(); condition.signal();
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; class DemoClass{ // 加减对象 private int number = 0; // 声明锁 private Lock lock = new ReentrantLock(); // 声明钥匙 private Condition condition = lock.newCondition(); /** * 加 1 */ public void increment() { try { lock.lock(); // 加锁 while (number != 0){ condition.await(); //等待} number++; System.out.println(currentThread().getName() + "加一成功,值为:" + number);// 通知其他等待的线程condition.signalAll(); }catch (Exception e){ e.printStackTrace(); }finally { lock.unlock(); //释放锁} } /** * 减一 */ public void decrement(){ try { lock.lock(); while (number != 1){ condition.await(); } number--; System.out.println(currentThread().getName() + "减一成功,值为:" + number); condition.signalAll(); }catch (Exception e){ e.printStackTrace(); }finally { lock.unlock(); } }
}
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; class DemoClass{ //通信对象:0--打印 A 1---打印 B 2----打印 C private int number = 0; //声明锁 private Lock lock = new ReentrantLock(); //声明钥匙 A private Condition conditionA = lock.newCondition(); //声明钥匙 B private Condition conditionB = lock.newCondition(); //声明钥匙 C private Condition conditionC = lock.newCondition();
}
3.4 线程间定制化通信
3.4.1 案例介绍
问题: A 线程打印 5 次 A,B 线程打印 10 次 B,C 线程打印 15 次 C 。
按照此顺序循环 10 轮
3.4.2 实现流程
代码如下:
// 标志位 AA 1 BB 2 CC 3
private int number = 1; Lock lock = new ReentrantLock();
private Condition conditionA = lock.newCondition();
private Condition conditionB = lock.newCondition();
private Condition conditionC = lock.newCondition(); // 5 次
public void printA(int j){ try { lock.lock(); while (number != 1){conditionA.await(); } System.out.println(currentThread().getName() + "输出 A,第" + j + " 轮开始"); // 输出 5 次 A for (int i = 0; i < 5; i++) { System.out.println("A"); } // 修改标志位 number = 2; //唤醒 BconditionB.signal(); } catch (Exception e){ e.printStackTrace(); } finally {lock.unlock(); }
} // 10 次
public void printB(int j){ try { lock.lock();while (number != 2){conditionB.await(); } System.out.println(currentThread().getName() + "输出 B,第" + j + " 轮开始"); //输出 10 次 B for (int i = 0; i < 10; i++) { System.out.println("B"); } // 修改标志位number = 3;//唤醒 CconditionC.signal(); } catch (Exception e){ e.printStackTrace(); }finally {lock.unlock(); }
}// 15 次
public void printC(int j){ try { lock.lock();while (number != 3){conditionC.await(); } System.out.println(currentThread().getName() + "输出 C,第" + j + " 轮开始"); //输出 15 次 C for (int i = 0; i < 15; i++) { System.out.println("C"); } System.out.println("-----------------------------------------"); // 修改标志位number = 1;//唤醒 AconditionA.signal(); } catch (Exception e){ e.printStackTrace(); } finally {lock.unlock(); }
}
测试类
/**
● 关键字实现线程交替加减
*/
public class TestVolatile { /** ● 交替加减 ● @param args */ public static void main(String[] args){ DemoClass demoClass = new DemoClass(); new Thread(() ->{ for (int i = 1; i <= 10; i++) { demoClass.printA(i); } }, "A 线程").start(); new Thread(() ->{for (int i = 1; i <= 10; i++) { demoClass.printB(i); } }, "B 线程").start(); new Thread(() ->{for (int i = 1; i <= 10; i++) {demoClass.printC(i); } }, "C 线程").start(); }
}