多线程
线程介绍
-
任务
-
进程 (Process )
- 一个进程里可以有多个线程,如视频中同是听到声音,看图像,看弹幕,等等
-
线程 (Thread)
-
Process与Thread
-
Process:程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念
-
Thread:线程则是执行程序的一次执行过程,他是一个动态的概念。是系统资源分配的单位
-
通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义。线程是CPU调度和执行的单位
-
-
多线程
线程实现(重点)
三种创建方式
- 继承Thread类(重点)
package chapter02.demo.demo01;
/**
* @program: Java-API
* @description: 创建线程方式一:继承Thread类,重写run()方法,调用start开启线程
* @author: Jam
* @create: 2022-04-20 15:12
**/
public class TestThread1 extends Thread{
@Override
public void run() {
//run方法线程体
for (int i = 0; i < 20; i++) {
System.out.println("在听狂神课-----");
}
}
//main线程,主线程
public static void main(String[] args) {
//创建线程对象
TestThread1 testThread1 = new TestThread1();
testThread1.start();
for (int i = 0; i < 1000; i++) {
System.out.println("在学多线程-----");
}
}
}
-
实现Runnable接口(重点)
package chapter02.demo.demo01; /** * @program: Java-API * @description: 创建线程方式二:实现Runnable接口,重写run方法,执行线程需要丢入runnable接口实现类,调用start() * @author: Jam * @create: 2022-04-20 23:12 **/ public class TestThread3 implements Runnable{ @Override public void run() { for (int i = 0; i < 20; i++) { System.out.println("在听狂神课-----"); } } public static void main(String[] args) { //创建runnable接口实现类 TestThread3 testThread3 = new TestThread3(); //创建线程对象,通过线程对象来开启我们的线程,代理 new Thread(testThread3).start(); for (int i = 0; i < 1000; i++) { System.out.println("我在学习多线程"); } } }
小结
不建议使用:避免OOP单继承局限性
继 承 T h r e a d 类 − − 》 子 类 继 承 T h r e a d 类 具 备 多 线 程 能 力 − − 》 启 动 线 程 : 子 类 对 象 . s t a r t ( ) 继承Thread类--》 子类继承Thread类具备多线程能力--》 启动线程:子类对象.start() 继承Thread类−−》子类继承Thread类具备多线程能力−−》启动线程:子类对象.start()
推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用
实 现 R u n n a b l e 接 口 − − 》 实 现 接 口 R u n n a b l e 具 有 多 线 程 的 能 力 − − 》 启 动 线 程 : 传 入 目 标 + T h r e a d ( 对 象 ) . s t a r t ( ) 实现Runnable接口--》实现接口Runnable 具有多线程的能力--》启动线程:传入目标+Thread(对象).start() 实现Runnable接口−−》实现接口Runnable具有多线程的能力−−》启动线程:传入目标+Thread(对象).start() -
实现Callable接口(了解)
package chapter02.demo.demo04;
import chapter02.demo.demo01.TestThread2;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;
/**
* @program: Java-API
* @description: 线程创建方式三:实现Callable接口
* @author: Jam
* @create: 2022-04-22 14:25
**/
public class TestCallable implements Callable<Boolean> {
private String url;//网络图片地址
private String name;//保存的文件名
public TestCallable() {
}
public TestCallable(String url, String name) {
this.url = url;
this.name = name;
}
@Override
public Boolean call() {
WebDownloader webDownloader = new WebDownloader();
webDownloader.downloader(url,name);
System.out.println(" 下载了到文件名为"+name);
return true;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
TestCallable testThread1 = new TestCallable("网上图片地址","1.jpg");
TestCallable testThread2 = new TestCallable("网上图片地址","2.jpg");
//创建执行服务
ExecutorService ser = Executors.newFixedThreadPool(2);
//提交执行
Future<Boolean> submit1 = ser.submit(testThread1);
Future<Boolean> submit2 = ser.submit(testThread2);
//获取结果
Boolean aBoolean1 = submit1.get();
Boolean aBoolean2 = submit1.get();
//关闭服务
ser.shutdown();
}
}
//下载器
class WebDownloader{
//下载方法
public void downloader(String url,String name) {
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
e.printStackTrace();
System.out.println("IO异常downloader方法出现问题");
}
}
}
龟兔赛跑案例
package chapter02.demo.demo03;
/**
* @program: Java-API
* @description: 多线程龟兔赛跑案例
* @author: Jam
* @create: 2022-04-21 23:21
**/
@SuppressWarnings("all")
public class Race implements Runnable {
private static String winner;
@Override
public void run() {
for (int i = 0; i <= 1000; i++) {
//模拟兔子睡觉
if (Thread.currentThread().getName().equals("兔子")){
try {
Thread.sleep(0);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//判断是否出现胜利者
if (gameOver(i)) {
break;
}
System.out.println(Thread.currentThread().getName() + "-->跑了" + i + "步");
}
}
//判断是否出现冠军
public boolean gameOver(int a) {
if (winner != null) {
return true;
} else if (a >= 1000) {
winner = Thread.currentThread().getName();
System.out.println("winner is" + winner);
return true;
}
return false;
}
public static void main(String[] args) {
Race race = new Race();
new Thread(race, "兔子").start();
new Thread(race, "乌龟").start();
}
}
线程开启不一定立即执行,由CPU调度执行
线程状态
模拟延时作用:放大问题的发生性
方法 | 说明 |
---|---|
setPriority(int newPrioity) | 更改线程优先级 |
static void sleep(long millis) | 在指定的毫秒数内让当前正在执行的线程休眠 |
void join() | 等待该程序终止 |
static void yield() | 暂停当前正在执行的线程对象,并执行其他线程 |
void interrupt() | 中断线程,不要使用 |
boolean isAlive() | 测试线程是否处于活动状态 |
线程休眠
package chapter02.demo.demo07;
import java.text.SimpleDateFormat;
import java.util.Date;
//模拟倒计时
public class TestSleep {
public static void main(String[] args) {
tenDown();
//打印系统现在时间
Date startTime = new Date(System.currentTimeMillis());//获取系统当前时间
while (true){
try {
Thread.sleep(1000);
System.out.println(
new SimpleDateFormat("HH:mm:ss").format(startTime)
);
startTime = new Date(System.currentTimeMillis());//更新时间
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//模拟倒计时
public static void tenDown(){
int num = 10;
while (true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("延时发生异常");
}
System.out.println(num--);
if (num<=0){
break;
}
}
}
}
线程礼让
线程礼让,是让当前正在执行的线程暂停,但不堵塞
将线程从运行状态转为就绪状态
让CPU重新调度,不一定能成功
public class TestYield {
//测试礼让线程
//礼让不一定成功,看CPU心情
public static void main(String[] args) {
MyYield myYield = new MyYield();
new Thread(myYield,"A").start();
new Thread(myYield,"B").start();
}
}
class MyYield implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"线程开始执行");
Thread.yield();//礼让
System.out.println(Thread.currentThread().getName()+"线程结束执行");
}
}
线程强制执行 join
是非常霸道的,强制执行的,相当于插队
package chapter02.demo.demo07;
//线程强制执行,测试join方法,
public class TestJoin implements Runnable{
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("VIP来了"+i);
}
}
public static void main(String[] args) throws InterruptedException {
TestJoin testJoin = new TestJoin();
Thread thread = new Thread(testJoin);
thread.start();
for (int i = 0; i < 500; i++) {
if (i==200){
thread.join();
}
System.out.println("main"+i);
}
}
}
观察测试线程状态
//观察测试线程状态
public class TestState{
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
System.out.println("线程休息1秒");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("/");
}
});
//观察状态
Thread.State state = thread.getState();
System.out.println(state);
//观察启动后
thread.start();//启动线程
state = thread.getState();
System.out.println(state);
while (state != Thread.State.TERMINATED){//只要线程不堵塞,就一直会执行
Thread.sleep(100);
state = thread.getState();//更新线程状态
System.out.println(state);//输出状态
}
//线程只能执行一次,死亡之后不能再被调用
}
}
线程优先级
线程优先级用数字表示,范围是1~10
优先级的设定在start()调度之前
方法 | 说明 |
---|---|
getPriority() | 获取优先级 |
setPriority(int xxx) | 改变优先级 |
//测试线程优先级
public class TestPriority {
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);
Thread thread6 = new Thread(myPriority);
//先设置优先级,再启动
thread1.start();
thread2.setPriority(1);
thread2.start();
thread3.setPriority(4);
thread3.start();
thread4.setPriority(Thread.MAX_PRIORITY);//MAX_PRIORITY=10
thread4.start();
thread5.setPriority(8);
thread5.start();
thread6.setPriority(7);
thread6.start();
}
}
class MyPriority implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"--->"+Thread.currentThread().getPriority());
}
}
优先级底只是意味着获得调度的概率底,并不是优先级低就不会被调用,这都是看CPU的调度
守护(Daemon)线程
线程分为用户线程和守护线程
虚拟机必须确保用户线程执行完毕
虚拟机不用等待守护线程执行完毕
后台记录操作日志,监控内存,垃圾回收等待,用到守护线程
//测试守护线程
//案例:上帝守护你
public class TestDDaemon {
public static void main(String[] args) {
God god = new God();
You you = new You();
Thread thread = new Thread(god);
thread.setDaemon(true);//默认是false表示是用户线程,正常的线程都是用户线程
thread.start();//上帝守护线程启动
new Thread(you).start();//用户线程启动
}
}
//上帝
class God implements Runnable {
@Override
public void run() {
while (true) {
System.out.println("上帝保佑着你");
}
}
}
//你
class You implements Runnable {
@Override
public void run() {
for (int i = 0; i < 36500; i++) {
System.out.println("你一生都开心的活着");
}
System.out.println("======goodbye! word!======");
}
}
线程同步(重点)
线程同步(synchronized)
多个线程操作同一个资源为线程同步
1. 并发:同一个对象被多个线程同时操作
形成条件:队列+锁(才能保证线程同步的一个安全性)
每一个对象都拥有一把锁
同步方法和同步块
synchronized关键字
synchronized关键字用来锁能被修改的,默认锁的是本身(this)
两种方法:
-
synchronized方法
使用synchronized修饰的方法控制对类成员变量的访问 访问修饰符 synchronized 返回类型 方法名(参数列表){……} 或者 synchronized 访问修饰符 返回类型 方法名(参数列表){……} synchronized就是为当前的线程声明一个锁
//不安全的买票 //线程不安全有负数 public class UnsafeBuyTicket { public static void main(String[] args) { BuyTicket buyTicket = new BuyTicket(); new Thread(buyTicket,"你").start(); new Thread(buyTicket,"我").start(); new Thread(buyTicket,"他").start(); } } class BuyTicket implements Runnable{ //票 private int ticketNums = 10; boolean flag = true; @Override public void run() { while (flag){ buy(); } } //用synchronized关键字,这里叫synchronized方法 private synchronized void buy(){ //判断是否有票 if (ticketNums<=0){ flag = false; return; } //模拟延迟 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } //买票 System.out.println(Thread.currentThread().getName()+"拿到"+ticketNums--+"张票"); } }
-
synchronized块
多个并发线程访问同一资源的同步代码块时
同一时刻只能有一个线程进入synchronized(this)同步代码块
当一个线程访问一个synchronized(this)同步代码块时,其他synchronized(this)同步代码块同样被锁定
当一个线程访问一个synchronized(this)同步代码块时,其他线程可以访问该资源的非synchronized(this)同步代码
package chapter02.demo.demo08.syn;
//不安全的取钱
//两个人同时去银行取钱
public class unsafeBank {
public static void main(String[] args) {
Account account = new Account(100,"儿童基金");
Drawing drawing1 = new Drawing(account,50,"小明");
Drawing drawing2 = new Drawing(account,100,"花花");
drawing1.start();
drawing2.start();
}
}
//账户
class Account {
int money;//余额
String name;//卡明
public Account(int money, String name) {
this.money = money;
this.name = name;
}
}
//银行:模拟取钱
class Drawing extends Thread {
Account account;//账户
//取了多少钱
int drawingMoney;
//现在手里还有多少钱
int nowMoney;
public Drawing(Account account,int drawingMoney,String name){
super(name);
this.account = account;
this.drawingMoney = drawingMoney;
}
@Override
public void run() {
synchronized (account){
//判断有没有钱
if (account.money-drawingMoney<0){
System.out.println(Thread.currentThread().getName()+"亲,钱不够了!");
return;
}
//模拟延迟放大问题的发生性
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//卡内余额 = 余额 - 取的钱
account.money = account.money-drawingMoney;
//你手里的钱
nowMoney = nowMoney+ drawingMoney;
System.out.println(account.name+"余额为:"+account.money);
System.out.println(this.getName()+"手里的钱"+nowMoney);
}
}
}
死锁
什么是死锁
多个线程各自占有一些共享资源﹐并且互相等待其他线程占有的资源才能运行﹐
而导致两个或者多个线程都在等待对方释放资源﹐都停止执行的情形.
某一个同步块同时拥有“两个以上对象的锁”时,就可能会发生“死锁”的问题.
Lock锁
ReentrantLock:可重入锁
import java.util.concurrent.locks.ReentrantLock;
//测试Lock锁
public class TestLock {
public static void main(String[] args) {
TestLock2 testLock2 = new TestLock2();
new Thread(testLock2).start();
new Thread(testLock2).start();
new Thread(testLock2).start();
}
}
class TestLock2 implements Runnable{
int ticketNums = 10;
//定义Lock锁
private final ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true){
try {
//加锁
lock.lock();
if (ticketNums>0){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(ticketNums--);
}else{
break;
}
}finally {
//解锁
lock.unlock();
}
}
}
}
synchronized和Lock的区别
线程通信问题
线程协作(线程通信/生产消费者模式)
线程通信分析
解决线程之间通信问题的方法
方法名 | 作用 |
---|---|
wait() | 表示线程一直等待,直到其他线程通知,与sleep不同,它会释放锁 |
wait(long timeout) | 指定等待的毫秒数 |
notify() | 唤醒一个处于等待状态的线程 |
notifyAll() | 唤醒同一个对象上所有调用wait()方法的线程,优先级别高的线程优先调度 |
解决线程之间通信问题方式一>>>>管理法
管理法
//测试:生产消费者模型>>>>>利用缓冲区解决(管理法)
public class TestPC {
public static void main(String[] args) {
SynContainer synContainer = new SynContainer();
new Productor(synContainer).start();
new Consumer(synContainer).start();
}
}
//生产者
class Productor extends Thread{
SynContainer container;
Productor(SynContainer synContainer){
this.container = synContainer;
}
//生产
@Override
public void run() {
for (int i = 0; i < 100; i++) {
container.push(new Chicken(i));
System.out.println("生产了--->"+i+"只鸡");
}
}
}
//消费者
class Consumer extends Thread{
SynContainer container;
Consumer(SynContainer synContainer){
this.container = synContainer;
}
//生产
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("消费了--->"+container.pop().id+"只鸡");
}
}
}
//产品
class Chicken{
int id;//产品编号
public Chicken(int id) {
this.id = id;
}
}
//缓冲区
class SynContainer{
//需要一个容器大小
Chicken[] chickens = new Chicken[10];
//容器计数器
int count = 0;
//生产着放入产品
public synchronized void push(Chicken chicken){
//如果产品满了就等待消费者消费
if (count==chickens.length){
//通知消费者消费,生产者等待
try {
//表示线程一直等待,直到其他线程通知
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果没有满,就需要丢入产品
chickens[count] = chicken;
count++;
//可以通知消费者消费了
this.notifyAll();
}
//消费者消费产品
public synchronized Chicken pop(){
//判断是否能消费
if (count==0){
//等待生产者生产
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果可以消费
count--;
Chicken chicken = chickens[count];
//消费完了通知生产者
this.notifyAll();
return chicken;
}
}
解决线程之间通信问题方式二>>>>信号灯法
信号灯法
package chapter02.demo.demo09;
//测试生产者,消费者问题2 信号灯法,标志位解决
public class TestPC2 {
public static void main(String[] args) {
TV tv = new TV();
new Watcher(tv).start();
new player(tv).start();
}
}
//生产者-->演员
class player extends Thread{
TV tv;
public player(TV tv) {
this.tv = tv;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
if (i%2==0){
this.tv.play("孔智超大撒谎比");
}else {
this.tv.play("孔智超还是大撒谎比");
}
}
}
}
//消费者-->观众
class Watcher extends Thread{
TV tv;
public Watcher(TV tv) {
this.tv = tv;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
if (i%2==0){
this.tv.watch();
}else {
this.tv.watch();
}
}
}
}
//产品--->节目
class TV {
//演员表演,观众等待
//观众观看,演员等待
String voice;//表演的节目
boolean flag = true;
//表演
public synchronized void play(String voice){
if (flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("演员表演了"+voice);
//通知观众可以观看
this.notifyAll();
this.voice = voice;
this.flag = !this.flag;
}
//观看
public synchronized void watch(){
if (flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("观看了"+voice);
//通知演员表演
this.notifyAll();
this.flag= !this.flag;
}
}
线程池
背景:经常创建和销毁、使用量特别大的资源,比如并发情况下的线程,对性能影响很大。
思路:提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。可以避免频繁创建销毁、实现重复利用。类似生活中的公共交通工具。
好处:
提高响应速度(减少了创建新线程的时间)
降低资源消耗(重复利用线程池中线程,不需要每次都创建)
便于线程管理(....)
corePoolSize:核心池的大小
maximumPoolSize:最大线程数
keepAliveTime:线程没有任务时最多保持多长时间后会终止
void execute(Runnable command)
package chapter02.demo.demo09;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
//测试线程池
public class TestPool {
public static void main(String[] args) {
//创建服务,创建线程池
//newFixedThreadPool 参数为:线程池大小
ExecutorService service = Executors.newFixedThreadPool(10);
//执行
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
//关闭链接
service.shutdown();
}
}
class MyThread implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
Future submit(Callable task)
package chapter02.demo.demo04;
import chapter02.demo.demo01.TestThread2;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;
/**
* @program: Java-API
* @description: 线程创建方式三:实现Callable接口
* @author: Jam
* @create: 2022-04-22 14:25
**/
public class TestCallable implements Callable<Boolean> {
private String url;//网络图片地址
private String name;//保存的文件名
public TestCallable() {
}
public TestCallable(String url, String name) {
this.url = url;
this.name = name;
}
@Override
public Boolean call() {
WebDownloader webDownloader = new WebDownloader();
webDownloader.downloader(url,name);
System.out.println(" 下载了到文件名为"+name);
return true;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
TestCallable testThread1 = new TestCallable("网上图片地址","1.jpg");
TestCallable testThread2 = new TestCallable("网上图片地址","2.jpg");
//创建执行服务
ExecutorService ser = Executors.newFixedThreadPool(2);
//提交执行
Future<Boolean> submit1 = ser.submit(testThread1);
Future<Boolean> submit2 = ser.submit(testThread2);
//获取结果
Boolean aBoolean1 = submit1.get();
Boolean aBoolean2 = submit1.get();
//关闭服务
ser.shutdown();
}
}
//下载器
class WebDownloader{
//下载方法
public void downloader(String url,String name) {
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
e.printStackTrace();
System.out.println("IO异常downloader方法出现问题");
}
}
}
总结
//线程三种创建方式
package chapter02.demo.demo09;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class ThreadNew {
public static void main(String[] args) {
//第一种启动方法
Thread1 thread1 = new Thread1();
thread1.start();
//第二种启动方式
new Thread(new Thread2()).start();
//第三种启动方式
FutureTask<Integer> futureTask = new FutureTask<Integer>(new Thread3());
new Thread(futureTask).start();
try {
System.out.println(futureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
//1.继承Thread
class Thread1 extends Thread{
@Override
public void run() {
System.out.println("Thread1");
}
}
//2.实现Runnable接口
class Thread2 implements Runnable{
@Override
public void run() {
System.out.println("Thread2");
}
}
//3.实现Callable<>接口
class Thread3 implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("Thread3");
return 100;
}
}
//线程同步
添加synchronized方法或synchronized块
静态代理
package chapter02.demo.demo05;
//静态代理模式总结:
//真实对象和代理对象都要实现同一个接口
//代理对象必须代理真实角色
//好处:
//代理对象可以做很多真实的对象做不了的事情
//真实对象专注做自己的事情
public class StacticProxy {
public static void main(String[] args) {
WeddingCompany weddingCompany = new WeddingCompany(new You());
weddingCompany.happyMarry();
}
}
interface Marry{
void happyMarry();
}
//真是角色
class You implements Marry{
@Override
public void happyMarry() {
System.out.println("张晨浩要结婚了,跟个傻逼一样一样的");
}
}
//代理角色,
class WeddingCompany implements Marry{
private Marry target;
public WeddingCompany(Marry target) {
this.target = target;
}
@Override
public void happyMarry() {
before();
this.target.happyMarry();
after();
}
private void after() {
System.out.println("结婚之后,收尾款");
}
private void before() {
System.out.println("结婚之前,布置现场");
}
}
Lambda表达式
推导lambda表达式
package chapter02.demo.demo06;
/*
* 推导lambda表达式
* */
public class Lambda {
//3:优化方式一
//静态内部类
static class Like2 implements ILike{
@Override
public void lambda() {
System.out.println("I like lambda2");
}
}
public static void main(String[] args) {
ILike like = new Like();
like.lambda();
//静态内部类
like = new Like2();
like.lambda();
//4:优化方式二
//局部内部类
class Like3 implements ILike{
@Override
public void lambda() {
System.out.println("I like lambda3");
}
}
like = new Like3();
like.lambda();
//5:优化方式三
//匿名内部类,没有类的名称,必须借助接口或者父类
like = new ILike() {
@Override
public void lambda() {
System.out.println("I like lambda4");
}
};
like.lambda();
//6:优化方式四
//lambda
like = ()->{
System.out.println("I like lambda5");
};
like.lambda();
}
}
//1.定义一个函数式接口
interface ILike{
void lambda();
}
//2.实现类
class Like implements ILike{
@Override
public void lambda() {
System.out.println("I like lambda1");
}
}
lambda表达式
package chapter02.demo.demo06;
public class TestLambdaTwo {
public static void main(String[] args) {
ILove love = null;
ILove love = (int a)-> {
System.out.println("I love you-->"+a);
};
//简化1:去掉参数类型
love = (a)-> {
System.out.println("I love you-->"+a);
};
//简化2:简化括号
love = a ->{
System.out.println("I love you-->"+a);
};
//简化3:去掉花括号
love = a -> System.out.println("I love you-->"+a);
love.love(520);
}
}
//定义函数式接口
interface ILove{
void love(int a);
}
//总结:
//函数式接口意思就是只有一个重写的方法
//lambda表达式只能有一行代码的情况下才能简化成一行,如果多行那就用代码块包裹
// 使用lambda表达式前提是接口为函数式接口
//多个参数也可以去掉参数类型,要去掉就都去掉,必须加上括号