3、Java8之lambda表达式复习
Lambda 是一个匿名函数,我们可以把 Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。
Lambda 表达式在Java 语言中引入了一个新的语法元素和操作符。这个操作符为 “->” , 该操作符被称
为 Lambda 操作符或剪头操作符。它将 Lambda 分为 两个部分:
左侧:指定了 Lambda 表达式需要的所有参数
右侧:指定了 Lambda 体,即 Lambda 表达式要执行的功能
代码演示
package com.atguigu.thread; @FunctionalInterface interface Foo{ // public void sayHello() ; public int add(int x,int y); //函数式接口可以有多个 default实现 //JDK1.8之后 接口里面可以有方法的实现 default int div(int x,int y) { return x/y; } //可以有多个静态函数 public static int sub(int x,int y) { return x-y; } } /** * * @Description: Lambda Express-----> 函数式编程 * 1 口诀:拷贝小括号(形参列表),写死右箭头 ->,落地大括号 {方法实现} * 2 什么是Lambda:有且只有一个public方法(@FunctionalInterface注解增强定义) * 3 JDK1.8之后可以有default方法默认实现 * 4 可以有静态方法实现 */ public class LambdaDemo { public static void main(String[] args) { //使用匿名内部类方式调用接口中的方法方式 // Foo foo = new Foo() { // @Override // public void sayHello() { // System.out.println("Hello!!"); // } // foo.sayHello(); //使用Lambda方式 Foo foo = (x,y)->{ System.out.println("Hello!! lambda !!"); return x+y; }; int result = foo.add(3,5); System.out.println("******result="+result); System.out.println("******result div="+foo.div(10, 2)); System.out.println("******result sub="+Foo.sub(10, 2)); } }
4、线程间通信
线程间通信的模型有两种:共享内存和消息传递,以下方式都是基本这两种模型来实现的。
我们来基本一道面试常见的题目来分析
场景: 两个线程,一个线程对当前数值加1,另一个线程对当前数值减1,要求 用线程间通信
4.1 synchronized实现
package com.rg.sync; //第一步 创建资源类,定义属性和操作方法 class Share { //初始值 private int number = 0; //+1的方法 public synchronized void incr() throws InterruptedException { //第二步 判断 干活 通知 while(number != 0) { //判断number值是否是0,如果不是0,等待 this.wait(); //在哪里睡,就在哪里醒 } //如果number值是0,就+1操作 number++; System.out.println(Thread.currentThread().getName()+" :: "+number); //通知其他线程 this.notifyAll(); } //-1的方法 public synchronized void decr() throws InterruptedException { //判断 while(number != 1) { this.wait(); } //干活 number--; System.out.println(Thread.currentThread().getName()+" :: "+number); //通知其他线程 this.notifyAll(); } } /** * * @Description: * 现在两个线程, * 可以操作初始值为零的一个变量,实现一个线程对该变量加1,一个线程对该变量减1,交替,来10轮。 * Java里面如何进行工程级别的多线程编写 * 1 多线程编程模板(套路)-----上 * 1.1 在高内聚低耦合的场景下:线程 操作 资源类 * 2 多线程编程模板(套路)-----中 * 2.1 判断 * 2.2 干活 * 2.3 通知 * 3 多线程编程模板(套路)-----下 * 防止虚假唤醒用while,不用if * 虚假唤醒例子:坐飞机,机长广播飞机上有不安全物品,需要全体人员下来然后工作人员检查.检查完之后,需要重新安检上飞机... */ public class ThreadDemo1 { //第三步 创建多个线程,调用资源类的操作方法 public static void main(String[] args) { Share share = new Share(); //创建线程 new Thread(()->{ for (int i = 1; i <=10; i++) { try { share.incr(); //+1 } catch (InterruptedException e) { e.printStackTrace(); } } },"AA").start(); new Thread(()->{ for (int i = 1; i <=10; i++) { try { share.decr(); //-1 } catch (InterruptedException e) { e.printStackTrace(); } } },"BB").start(); new Thread(()->{ for (int i = 1; i <=10; i++) { try { share.incr(); //+1 } catch (InterruptedException e) { e.printStackTrace(); } } },"CC").start(); new Thread(()->{ for (int i = 1; i <=10; i++) { try { share.decr(); //-1 } catch (InterruptedException e) { e.printStackTrace(); } } },"DD").start(); } }
**结果分析:**当只有AA,BB线程时,一切运行正常, AA::1和BB::0 轮流执行
当增加CC、DD线程时,会出现虚假唤醒的情况,
原因分析:
4.2 Lock 方案
package com.rg.lock; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @author lxy * @version 1.0 * @Description * @date 2022/4/25 17:30 */ //第一步 创建资源类,定义属性和操作方法 class Share{ private int number = 0; //创建Lock private Lock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); //+1 public void incr() 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 decr() throws InterruptedException { //上锁 lock.lock(); try { //判断 while (number!=1){ condition.await(); } //干活 number--; System.out.println(Thread.currentThread().getName()+" :: "+number); //通知 condition.signalAll(); }finally { lock.unlock(); } } } /** * * @Description: * 现在两个线程, * 可以操作初始值为零的一个变量,实现一个线程对该变量加1,一个线程对该变量减1,交替,来10轮。 * Java里面如何进行工程级别的多线程编写 * 1 多线程编程模板(套路)-----上 * 1.1 在高内聚低耦合的场景下:线程 操作 资源类 * 2 多线程编程模板(套路)-----中 * 2.1 判断 * 2.2 干活 * 2.3 通知 * 3 多线程编程模板(套路)-----下 * 防止虚假唤醒用while,不用if */ 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(); } }
4.3 线程间定制化调用通信
三个线程启动,要求如下:
AA打印5次,BB打印10次,CC打印15次.
接着
AA打印5次,BB打印10次,CC打印15次
…来10轮
实现代码
package com.rg.lock; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @author lxy * @version 1.0 * @Description * @date 2022/4/27 16:01 */ //第一步 创建资源类 class ShareResource{ //定义标志位 private int flag = 1;//1 AA 2 BB 3 CC //创建Lock锁 private Lock lock = new ReentrantLock(); //创建三个Condition,也就是三把钥匙 private Condition c1 = lock.newCondition(); private Condition c2 = lock.newCondition(); private Condition c3 = lock.newCondition(); //打印5次,参数第几轮 public void print5(int loop) throws InterruptedException { //上锁 lock.lock(); try { //判断 while (flag!=1){ //等待 c1.await(); } //干活 for (int i = 1; i <= 5; i++) { System.out.println(Thread.currentThread().getName()+" :: "+i+" : 轮数: "+loop); } //通知 flag = 2; c2.signal();//通知BB线程(精准通知) }finally { //释放锁 lock.unlock(); } } //打印10次,参数第几轮 public void print10(int loop) throws InterruptedException { //上锁 lock.lock(); try { //判断 while (flag!=2){ //等待 c2.await(); } //干活 for (int i = 1; i <= 10; i++) { System.out.println(Thread.currentThread().getName()+" :: "+i+" : 轮数: "+loop); } //通知 flag = 3; c3.signal();//通知CC线程(精准通知) }finally { //释放锁 lock.unlock(); } } //打印15次,参数第几轮 public void print15(int loop) throws InterruptedException { //上锁 lock.lock(); try { //判断 while (flag!=3){ //等待 c3.await(); } //干活 for (int i = 1; i <= 15; i++) { System.out.println(Thread.currentThread().getName()+" :: "+i+" : 轮数: "+loop); } //通知 flag = 1; c1.signal();//通知AA线程(精准通知) }finally { //释放锁 lock.unlock(); } } } /** * * @Description: * 多线程之间按顺序调用,实现A->B->C * 三个线程启动,要求如下: * * AA打印5次,BB打印10次,CC打印15次 * 接着 * AA打印5次,BB打印10次,CC打印15次 * ......来10轮 * * 在线程定制化通信中,使用Lock相比使用syns可以做到精准定位/精准打击. * 多线程编程模板(套路)-----上 * 1 在高内聚低耦合的场景下:线程 操作 资源类 * 2 判断/干活/通知 * 3 多线程交互中,必须要防止多线程的虚假唤醒,也即(判断只用while,不能用if) * 4 标志位 */ public class ThreadDemo3 { public static void main(String[] args) { ShareResource shareResource = new ShareResource(); new Thread(()->{ for (int i = 1; i <= 10 ; i++) { try { shareResource.print5(i); } catch (InterruptedException e) { e.printStackTrace(); } } },"AA").start(); new Thread(()->{ for (int i = 1; i <= 10 ; i++) { try { shareResource.print10(i); } catch (InterruptedException e) { e.printStackTrace(); } } },"BB").start(); new Thread(()->{ for (int i = 1; i <= 10 ; i++) { try { shareResource.print15(i); } catch (InterruptedException e) { e.printStackTrace(); } } },"CC").start(); } }