一、介绍
- 线程之间的通信问题:生产者和消费者问题!
- 线程之间的等待唤醒、通知唤醒
- 线程之间交替执行,线程A、线程B操作同一个变量num=0
- 线程A:num+1
- 线程B:num-1
- 总结
① 判断线程是否需要等待
② 业务逻辑
③ 通知唤醒
二、Synchronized锁版本
-
下面代码存在虚假唤醒问题(如果存在ABCD四个线程,2个加2个减,就会出现虚假唤醒问题)
package pc; /** * @author swaggyhang * @create 2023-07-02 9:37 */ public class Test03 { 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(); } }
-
虚假唤醒代码演示
package pc; /** * @author swaggyhang * @create 2023-07-02 9:37 */ public class Test03 { 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 { 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(); } }
-
解决虚假唤醒问题
-
解决虚假唤醒代码演示
package pc; /** * @author swaggyhang * @create 2023-07-02 9:37 */ public class Test03 { 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 (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(); } }
三、Lock锁版本
-
Synchronized和Lock对比
-
Condition接口
-
基本代码演示(存在ABCD不是顺序执行的问题)
package pc; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @author swaggyhang * @create 2023-07-02 10:06 */ public class Test04 { public static void main(String[] args) { Data2 data2 = new Data2(); new Thread(() -> { for (int i = 0; i < 10; i++) { try { data2.increment(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "A").start(); new Thread(() -> { for (int i = 0; i < 10; i++) { try { data2.decrement(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "B").start(); new Thread(() -> { for (int i = 0; i < 10; i++) { try { data2.increment(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "C").start(); new Thread(() -> { for (int i = 0; i < 10; i++) { try { data2.decrement(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "D").start(); } } // 资源类 class Data2 { // 共享变量 private int number = 0; // 获取lock对象 Lock lock = new ReentrantLock(); // 获取condition对象 Condition condition = lock.newCondition(); // 加1 public void increment() throws InterruptedException { // 加锁 lock.lock(); try { // 判断等待 while (number != 0) { condition.await(); } // 业务逻辑 number++; System.out.println(Thread.currentThread().getName() + "=>" + number); // 通知唤醒 condition.signalAll(); } finally { // 解锁 lock.unlock(); } } // 减1 public void decrement() throws InterruptedException { lock.lock(); try { while (number == 0) { condition.await(); } number--; System.out.println(Thread.currentThread().getName() + "=>" + number); condition.signalAll(); } finally { lock.unlock(); } } }
-
Condition精准通知唤醒线程(ABC三个线程按照顺序依次执行)
package pc; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @author swaggyhang * @create 2023-07-02 11:27 */ public class Test05 { public static void main(String[] args) { Data3 data3 = new Data3(); new Thread(() -> { for (int i = 0; i < 10; i++) { data3.printA(); } }, "A").start(); new Thread(() -> { for (int i = 0; i < 10; i++) { data3.printB(); } }, "B").start(); new Thread(() -> { for (int i = 0; i < 10; i++) { data3.printC(); } }, "C").start(); } } class Data3 { private final Lock lock = new ReentrantLock(); private final Condition condition = lock.newCondition(); // 标志位 1表示线程A 2表示线程B 3表示线程C private int number = 1; public void printA() { lock.lock(); try { while (number != 1) { condition.await(); } number = 2; System.out.println(Thread.currentThread().getName() + "=> AAAA"); condition.signalAll(); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } public void printB() { lock.lock(); try { while (number != 2) { condition.await(); } number = 3; System.out.println(Thread.currentThread().getName() + "=> BBBB"); condition.signalAll(); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } public void printC() { lock.lock(); try { while (number != 3) { condition.await(); } number = 1; System.out.println(Thread.currentThread().getName() + "=> CCCC"); condition.signalAll(); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } }