Java学习_Day18
今天的学习内容
一、线程间通信
二、线程池
三、Lamdba表达式
一、线程间的通信
理解:利用等待(wait)和唤醒(notify)机制,让多个线程之间达到协同合作的目的
注意:等待(wait)唤醒(notify) 都必须被锁对象调用
等待和唤醒案例(生产者和消费者)
包子类(共享资源)`
public class BaoZi{
//皮
String pi;
//馅
String xian;
//状态 有(true) 没有(false)
boolean flag;
}
生产者线程(包子铺)
public class BaoziPu extends Thread{
//共享资源(作为锁对象)
private BaoZi bz;
//创建对象的时候给bz对象赋值
public BaoziPu(BaoZi bz){
this.bz=bz;
}
@Override
public void run(){
int count=0; //计数器
while(true){
//先对包子的状态进行判断,有(等待),没有(做包子)
synchronized(bz){
//有包子(等待)
if(bz.flag){
try{
bz.wait();
}catch(Exception e){
e.printStackTrace();
}
}
//等待完了没有包子(做包子)
try{
//做包子得花费1秒钟的时间
Thread.sleep(1000);
}catch(Exception e){
e.printStackTrace();
}
//表示做"薄皮"+"三鲜馅"的包子
if(count%2==0){
bz.pi="薄皮";
bz.xian="三鲜馅"
}else if(count%2==1){
//表示做"冰皮"+"牛肉馅"的包子
bz.pi="冰皮";
bz.xian="牛肉馅";
}
count++;
//包子做好了,改变包子的状态为有包子
bz.flag=true;
System.out.println(bz.pi+bz.xian+"包子做好了,吃货可以吃包子了...");
bz.nofiy(); //唤醒顾客吃包子
}
}
}
}
消费者线程(顾客)
public class Customer extends Thread{
private BaoZi bz;
public Customer(BaoZi bz){
this.bz=bz;
}
@Override
public void run(){
while(true){
synchronized(bz){
//如果没有包子等待,有包子吃包子
if(!bz.flag){
try{
bz.wait();
}catch(Exception e){
e.printStackTrace();
}
}
//包子做好了,就可以吃包子了
System.out.println("顾客开始吃"+bz.pi+bz.xian+"的包子");
bz.flag=false; //吃完包子,包子的状态给为false
bz.notify(); //唤醒包子铺做包子
}
}
}
}
测试类
public class Demo{
public static void main(String[] args){
BaoZi bz=new BaoZi();
//创建包子铺线程对象,传递共享资源 “包子对象”
BaoziPu bzp=new BaoziPu(bz);
bzp.start();
//创建顾客线程对象,传递共享资源 “包子对象”
Customer cs=new Customer(bz);
cs.start();
}
}
二、线程池
JDK1.5之后就提供了线程池,方便执行线程任务
//第一步:获取线程池对象
ExecutorService service=Executors.newFixedThreadPool(2); //包含2个线程的线程池
//第二步:提交线程任务
service.submit(new Runnable(){
@Override
public void run(){
System.out.println(Thread.currentThread().getName()+"线程任务执行了");
}
});
service.submit(new Runnable(){
@Override
public void run(){
System.out.println(Thread.currentThread().getName()+"线程任务执行了");
}
});
//第三步:销毁线程池(不建议),线程池就没有用了。
service.shutdown();
三、Lamdba表达式
函数式接口:
只能有一个抽象方法的接口,但是可以有其他方法。
@FunctionalInterface 标记接口为函数式接口
使用Lamdba表达式的前提
1)必须要有一个函数式接口
2)Lambda表达式可以理解为函数式接口的实例实现(可以有效优化匿名内部类代码的冗余)
Lamdba表达式的格式
//标准格式
(Type1 param1,Type2 param2)->{… return 返回值;}
//省略数据类型
(param1,param2)->{… return 返回值;}
//省略{}以及return语句。 【如果语句体只有一条语句】
(param1,param2)-> 语句体;
//省略() 【如果参数只有一个,才能省略()】
param1-> 语句体;
Lamdba表达式的使用步骤
1)需要先有一个函数式接口
2)写一个方法,把函数式接口作为方法的参数
3)调用方法,传递的实际参数对函数式接口进行实现
函数式接口实现方式一:使用匿名内部类(代码冗余)
函数式接口实现方式二:使用Lamdba表达式(减少代码冗余)
//1)需要先有一个函数式接口
@FunctionalInterface
public interface Cook{
public abstract void makeFood(); //做食物
}
//写一个测试类
public class Demo1{
public static void main(String[] args){
//3)调用方法,匿名内部类对函数式接口进行实现
invokeCook(
new Cook(){
public void makeFood(){
System.out.println("烹饪大米饭");
}
}
);
//3)调用方法,Lamdb表达式对函数式接口进行实现
invokeCook(
()->{
System.out.println("烹饪小米粥");
}
);
}
//2)写一个方法,把函数式接口作为方法的参数
public static void invokeCook(Cook cook){
cook.makeFood();
}
}
lambda表达式就是简化匿名内部类的写法
上面时候用到匿名内部类并要复写里面的方法,就可以考虑使用lambda表达式来简化
Java学习第19天内容链接:
https://blog.csdn.net/LJN951118/article/details/89409936