Lamda表达式
-
λ:希腊字母表中排序11位的字母(Lamda);
-
作用:避免匿名内部类定义过多;
-
函数式编程的逻辑
1)(params)-> expression[表达式]
2)(params)-> statement[语句]
3)(params)-> {statements}
new Thread(()->System.out.println("Lamda表达式")).start();
-
理解Function Interface(函数式接口)是学习Java8 Lamda的关键所在
函数式接口定义:
-
任何接口,如果只包含唯一一个抽象方法,那么他就是一个函数式接口;
-
对于函数式接口,我们可以通过Lamda表达式来创建该接口的对象
-
// 函数式接口----推导Lamda表达式 public class FunctionInterface { public static void main(String[] args) { // 7 lamda表达式 Test test = (String name)->{ System.out.println(name + " love fly!"); }; test.love("wa"); // 8 简化一:参数类型 test = (name)->{ System.out.println(name + " love fly!"); }; test.love("wa"); // 9 简化二:简化括号 test = name->{ System.out.println(name + " love fly!"); }; test.love("wa"); // 10 简化三:去掉花括号 test = name->System.out.println(name + " love fly!"); // 总结: // lamda表达式只能有一行代码的情况下才能简化为一行,如果有多行,需要用代码块包裹 // 前提是接口必须为函数式接口 // 多个参数也可以去掉参数类型,要去掉就都去掉,必须加上括号 test.love("wa"); TestLamda lamda = new Lamda(); lamda.lamda(); lamda = new Lamda2(); lamda.lamda(); // 4局部内部类 class Lamda3 implements TestLamda { @Override public void lamda() { System.out.println("Java 博大精深!开发前辈-佩服之至33333!"); } } lamda = new Lamda3(); lamda.lamda(); // 5匿名内部类,没有类的名称,必须借助接口或者父类 lamda = new TestLamda(){ @Override public void lamda() { System.out.println("Java 博大精深!开发前辈-佩服之至44444!"); } }; lamda.lamda(); // 6lamda简化 lamda = ()->{ System.out.println("Java 博大精深!开发前辈-佩服之至55555!"); }; lamda.lamda(); } // 3静态内部类 static class Lamda2 implements TestLamda { @Override public void lamda() { System.out.println("Java 博大精深!开发前辈-佩服之至22222!"); } } } // 1定义一个函数式接口 interface TestLamda { void lamda(); } // 2实现类 class Lamda implements TestLamda { @Override public void lamda() { System.out.println("Java 博大精深!开发前辈-佩服之至!"); } } interface Test{ void love(String name); }
线程停止
-
线程五大状态:
-
创建状态:Thread t = new Thread()----------线程对象创建就进入到新生状态
-
就绪状态:当调用start()方法,线程进入就绪状态
-
阻塞状态:调用sleep、wait或者同步锁定时,线程进入阻塞状态,代码不会往下执行线程,阻塞接触后,重新进入就绪状态,等待CPU调度执行
-
运行状态:线程开始执行线程体的代码块
-
死亡状态:线程中断或结束,就会进入死亡状态,不能再次启动
-
-
不推荐使用JDK提供的stop()、destroy()方法【已废弃】
-
推荐使用标志位去让线程自动停止
// 1,通过标志位停止线程 // 2,建议设置次数,尽量避免死循环 // 3,不要使用stop,destroy等过时的方法(有bug或者弊端) public class StopThread implements Runnable{ // 1,定义线程体使用的标识 private boolean judge = true; @Override public void run() { // 2,线程体使用该方法 int i= 0; while (judge){ System.out.println("线程正在执行中!"+i++); } } // 3,对外提供方法改变标识 private void stop(){ this.judge=false; } public static void main(String[] args) { StopThread stopThread = new StopThread(); new Thread(stopThread).start(); for (int i = 0 ; i < 100 ; i++){ System.out.println("Main!"+i); if (i == 89){ stopThread.stop(); System.out.println("线程停止!"); } } } }
线程休眠
-
sleep(时间):指定当前线程阻塞的毫秒数 1000毫秒 = 1秒
-
异常:InterruptedException
-
sleep时间到达后线程进入就绪状态
-
sleep可以模拟网络延时,倒计时
-
每一个对象都已一个锁,sleep不会释放锁
-
模拟网络延时:
// 线程休眠----模拟网络延时,放到问题的发生性 public class SleepThread implements Runnable{ private Integer number = 10; @Override public void run() { while (true){ if (number<=0){ break; } // 模拟网络延时 try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"--》拿到了第"+number--+"票!"); } } public static void main(String[] args) { SleepThread sleepThread = new SleepThread(); // 线程不安全 new Thread(sleepThread,"小明").start(); new Thread(sleepThread,"小军").start(); new Thread(sleepThread,"小杨").start(); } }
-
模拟倒计时----以及获取当前时:分:秒:
import java.text.SimpleDateFormat; import java.util.Date; // 模拟倒计时 public class SleepThread2 implements Runnable{ private Integer time = 30; @Override public void run() { Date nowTime = new Date(System.currentTimeMillis());// 获取当前时间 while (true){ if(time<0) { break; }else{ try { Thread.sleep(1000); System.out.println(new SimpleDateFormat("HH:mm:ss").format(nowTime)); nowTime = new Date(System.currentTimeMillis());// 获取当前时间 } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(time--); } } public static void main(String[] args) { SleepThread2 sleepThread2 = new SleepThread2(); new Thread(sleepThread2).start(); } }
线程礼让(yield)
-
礼让线程,让当前正在执行的线程展厅,但不阻塞
-
将线程从运行状态转为就绪状态
-
让CPU重新调度,但不一定成功!得看CPU如何处理
// 线程礼让 // 礼让不一定成功,看CPU心情 public class YieldThread { public static void main(String[] args) { MyYield myYield = new MyYield(); new Thread(myYield,"threadOne").start(); new Thread(myYield,"threadTwo").start(); } } class MyYield implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"线程开始执行!"); Thread.yield(); System.out.println(Thread.currentThread().getName()+"线程停止执行!"); } }
-
礼让不成功:
-
礼让成功:
线程强制执行(Join)
-
Join合并线程,待此线程执行完成后,再执行其他线程,其他线程阻塞
-
可以想象成插队
// 线程强制执行----Join public class JoinThread implements Runnable{ @Override public void run() { for(int i = 0 ; i< 100 ; i++ ){ System.out.println("Vip线程!"+i); } } public static void main(String[] args) throws InterruptedException { JoinThread joinThread = new JoinThread(); Thread thread = new Thread(joinThread); thread.start(); for(int i = 0 ; i < 100 ; i++){ if(i == 50){ thread.join(); // 类似于插队,让thread线程先全部跑完,再接着跑其他线程 } System.out.println("Main"+i); } } }
线程状态观测
-
new 尚未启动的线程处于此状态
-
runnable 在Java虚拟机中执行的线程出于此状态
-
blocked 被阻塞等待监视器锁定的线程出于此状态
-
waiting 正在等待另一个线程执行特定动作的线程处于此状态
-
time_waiting 正在等待另一个线程执行动作到达指定等待时间的线程处于此状态
-
terminated 已退出的线程处于此状态
// 观察线程状态 public class ObservationThread { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(()->{ for (int i = 0 ; i < 5 ; i++){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("======================="); }); // 观察状态 // new Thread.State state = thread.getState(); System.out.println(state); // runnale thread.start(); state = thread.getState(); System.out.println(state); // 线程不终止,就一直输出状态 while (state != Thread.State.TERMINATED){ Thread.sleep(100); state = thread.getState(); System.out.println(state); } // 停止之后再尝试运行,会报错 thread.start(); } }
线程优先级(Priority)
-
Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行
-
线程的优先级用数字标识,范围从1~10
-
Thread.MIN_PRIORITY = 1;
-
Thread.MAX_PRIORITY = 10;
-
Thread.NORM_PRIORITY = 5;
-
-
设置了线程优先级只是让该线程有更大的可能被CPU先调度,并不是指优先级高的就一定先执行(性能倒置),且一般线程的优先级在start()调度前设置
-
使用一下方式改变或获取优先级
-
getPriority()
-
setPriority()
-
import javafx.scene.layout.Priority; // 线程优先级 public class PriorityThread extends Thread{ public static void main(String[] args) { System.out.println(Thread.currentThread().getName()+"-》"+Thread.currentThread().getPriority()); MyPriority myPriority = new MyPriority(); Thread thread1 = new Thread(myPriority); Thread thread2 = new Thread(myPriority); Thread thread3 = new Thread(myPriority); Thread thread4 = new Thread(myPriority); Thread thread5 = new Thread(myPriority); thread1.setPriority(1); thread2.setPriority(3); thread3.setPriority(5); thread4.setPriority(7); thread5.setPriority(10); thread1.start(); thread2.start(); thread3.start(); thread4.start(); thread5.start(); } } class MyPriority implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"-》"+Thread.currentThread().getPriority()); } }
守护(Daemon)线程
-
线程分为用户线程和守护线程
-
虚拟机必须确保用户线程执行完毕
-
虚拟机不用等待守护线程执行完毕(后台记录操作日志、监控内存、垃圾回收)
// 守护线程 public class DaemonThread { public static void main(String[] args) { God god = new God(); Me me = new Me(); Thread thread = new Thread(god); thread.setDaemon(true);// 默认是false,表示是用户线程,正常的线程 thread.start();// 启动守护线程 new Thread(me).start(); } } // 上帝 class God implements Runnable{ @Override public void run() { while (true){ System.out.println("上帝保佑着你"); } } } // 你 class Me implements Runnable{ @Override public void run() { for (int i = 0 ; i< 36500 ;i++){ System.out.println("你开心的活了一生!"+i); } System.out.println("GoodBye!The World!"); } }
-
守护线程会随着用户线程结束而跑一会儿再结束
线程同步机制(***重要)
-
并发:同一个对象被多个线程同时操作--》即多个线程操作同一个资源
-
为了解决并发问题,我们需要用到线程同步:线程同步实际上是一种等待机制,多个需要同时访问此对象的线程进入这个对象的等待池,形成队列,等待前面线程使用完毕,下一个线程再使用;
-
线程同步条件:队列+锁 ----》解决线程安全
-
线程同步的实现及问题:
-
实现:在访问时,加入锁机制-->synchronized,当一个线程获得对象的排它锁,会独占资源,其他线程必须等待,使用后释放锁即可;
-
问题一:一个线程持有锁会导致其他所有需要此锁的线程挂起;
-
问题二:在多线程的竞争下,加锁,释放锁会导致比较多的上下文切换和调度延时,引起性能问题;
-
问题三:如果一个优先级高的线程等待一个一个优先级低的线程释放锁,会导致优先级倒置,引起性能问题
-