线程之间的通信机制
1.首先我们回顾一下面试题:
两个线程,一个线程打印1-52,另一个打印字母A-Z打印顺序为12A34B...5152Z, 要求用线程间通信
这个面试题就就是完全考察线程之间的通信机制,常用的技术分为二种
- 一种是Object 类中的自带的 wait 和 notify 机制,
- 二是 lock中的通信机制 Condition接口中的 await 和 signal 方法。
线程间通信:1、生产者+消费者2、通知等待唤醒机制
- Object 类中的自带的 wait 和 notify 机制实现, synchronized用来办证线程安全
package com.atguigu.thread; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; class ShareDataOne//资源类 { private int number = 0;//初始值为零的一个变量 public synchronized void increment() throws InterruptedException { //1判断 if(number !=0 ) { this.wait(); } //2干活 ++number; System.out.println(Thread.currentThread().getName()+"\t"+number); //3通知 this.notifyAll(); } public synchronized void decrement() throws InterruptedException { // 1判断 if (number == 0) { this.wait(); } // 2干活 --number; System.out.println(Thread.currentThread().getName() + "\t" + number); // 3通知 this.notifyAll(); } } /** * * @Description: *现在两个线程, * 可以操作初始值为零的一个变量, * 实现一个线程对该变量加1,一个线程对该变量减1, * 交替,来10轮。 * @author xialei * * * 笔记:Java里面如何进行工程级别的多线程编写 * 1 多线程变成模板(套路)-----上 * 1.1 线程 操作 资源类 * 1.2 高内聚 低耦合 * 2 多线程变成模板(套路)-----下 * 2.1 判断 * 2.2 干活 * 2.3 通知 */ public class NotifyWaitDemoOne { public static void main(String[] args) { ShareDataOne sd = new ShareDataOne(); new Thread(() -> { for (int i = 1; i < 10; i++) { try { sd.increment(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }, "A").start(); new Thread(() -> { for (int i = 1; i < 10; i++) { try { sd.decrement(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }, "B").start(); } }
注意点:线程通信最好不要用 if 去判断,用 while 去判断,因为用 if 去判断容易造成虚假唤醒,以下是修改之后的数据
package com.atguigu.thread; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import org.omg.IOP.Codec; class ShareData//资源类 { private int number = 0;//初始值为零的一个变量 public synchronized void increment() throws InterruptedException { //判断 while(number!=0) { this.wait(); } //干活 ++number; System.out.println(Thread.currentThread().getName()+" \t "+number); //通知 this.notifyAll();; } public synchronized void decrement() throws InterruptedException { //判断 while(number!=1) { this.wait(); } //干活 --number; System.out.println(Thread.currentThread().getName()+" \t "+number); //通知 this.notifyAll(); } } /** * * @Description: *现在两个线程, * 可以操作初始值为零的一个变量, * 实现一个线程对该变量加1,一个线程对该变量减1, * 交替,来10轮。 * @author xialei * * * 笔记:Java里面如何进行工程级别的多线程编写 * 1 多线程变成模板(套路)-----上 * 1.1 线程 操作 资源类 * 1.2 高内聚 低耦合 * 2 多线程变成模板(套路)-----下 * 2.1 判断 * 2.2 干活 * 2.3 通知 */ public class NotifyWaitDemo { public static void main(String[] args) { ShareData sd = new ShareData(); new Thread(() -> { for (int i = 1; i <= 10; i++) { try { sd.increment(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "A").start(); new Thread(() -> { for (int i = 1; i <= 10; i++) { try { sd.decrement(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "B").start(); new Thread(() -> { for (int i = 1; i <= 10; i++) { try { sd.increment(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "C").start(); new Thread(() -> { for (int i = 1; i <= 10; i++) { try { sd.decrement(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "D").start(); } } /* * * * 2 多线程变成模板(套路)-----下 * 2.1 判断 * 2.2 干活 * 2.3 通知 * 3 防止虚假唤醒用while * * * */
使用 Condition去做
package com.atguigu.thread; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import org.omg.IOP.Codec; class ShareData//资源类 { private int number = 0;//初始值为零的一个变量 private Lock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); public void increment() throws InterruptedException { lock.lock(); try { //判断 while(number!=0) { condition.await(); } //干活 ++number; System.out.println(Thread.currentThread().getName()+" \t "+number); //通知 condition.signalAll(); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } public void decrement() throws InterruptedException { lock.lock(); try { //判断 while(number!=1) { condition.await(); } //干活 --number; System.out.println(Thread.currentThread().getName()+" \t "+number); //通知 condition.signalAll(); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } /*public synchronized void increment() throws InterruptedException { //判断 while(number!=0) { this.wait(); } //干活 ++number; System.out.println(Thread.currentThread().getName()+" \t "+number); //通知 this.notifyAll();; } public synchronized void decrement() throws InterruptedException { //判断 while(number!=1) { this.wait(); } //干活 --number; System.out.println(Thread.currentThread().getName()+" \t "+number); //通知 this.notifyAll(); }*/ } /** * * @Description: *现在两个线程, * 可以操作初始值为零的一个变量, * 实现一个线程对该变量加1,一个线程对该变量减1, * 交替,来10轮。 * * * 笔记:Java里面如何进行工程级别的多线程编写 * 1 多线程变成模板(套路)-----上 * 1.1 线程 操作 资源类 * 1.2 高内聚 低耦合 * 2 多线程变成模板(套路)-----下 * 2.1 判断 * 2.2 干活 * 2.3 通知 */ public class NotifyWaitDemo { public static void main(String[] args) { ShareData sd = new ShareData(); new Thread(() -> { for (int i = 1; i <= 10; i++) { try { sd.increment(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "A").start(); new Thread(() -> { for (int i = 1; i <= 10; i++) { try { sd.decrement(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "B").start(); new Thread(() -> { for (int i = 1; i <= 10; i++) { try { sd.increment(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "C").start(); new Thread(() -> { for (int i = 1; i <= 10; i++) { try { sd.decrement(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "D").start(); } } /* * * * 2 多线程变成模板(套路)-----下 * 2.1 判断 * 2.2 干活 * 2.3 通知 * 3 防止虚假唤醒用while * * * */
有志者、事竟成,破釜沉舟,百二秦关终属楚;
苦心人、天不负,卧薪尝胆,三千越甲可吞吴.
加油吧,致每个正在奋斗路上的你!!!