01.第一章:线程-等待唤醒机制_线程间通信:
1).“线程间通信”:两个线程是在两个相互隔离的“线程栈”中独立运行;但有些业务需要两个线程来协作完成,这样就需要两个线程有相互协作、配合的能力。
2).两个线程进行协作,就需要相互通信,才能共同完成一个任务。
02.第一章:线程-等待唤醒机制_等待与唤醒机制:
1).“等待与唤醒”就是两个线程进行相互协作的一个体现;
2).例如两个线程工作:
1).一个线程要生产一些东西;
2).一个线程要获取那个线程生成的东西;
很可能会产生一种情况:获取的线程在获取时,生产的线程还没有生产出来东西;获取的线程就
不能获取到东西,这钟情况在软件运行期间是不允许发生的。如果取不到可以等一会。
解决方式:
1).当获取线程去取东西时,发现没有东西,可以“等待”;
2).当生产的线程生产出来东西时,可以“唤醒”某个、所有等待的线程去取东西。
03.第一章:线程-等待唤醒机制_生产者与消费者的问题:
1).定义“包子铺”:
public class BaoZiPu {
private List baoZiList = new ArrayList<>();
//设置包子
public synchronized void setBaoZi(String s) {
baoZiList.add(s);
//让在本对象锁上等待的线程--唤醒
this.notify();
}
//获取包子
public synchronized String getBaoZi(){
if (baoZiList.size() == 0) {//没有包子了
//让持有本对象锁的线程-->等待
try {
System.out.println("线程:" + Thread.currentThread().getName() + " 开始等待....");
this.wait();//释放锁
System.out.println("线程:" + Thread.currentThread().getName() + " 被唤醒....");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//取包子
String s = baoZiList.remove(0);
System.out.println("线程:" + Thread.currentThread().getName() + " 取走一个:" + s);
return s;
}
}
2).“生产者”线程:
public class SetThread extends Thread{
private BaoZiPu bzp ;
public SetThread(BaoZiPu bzp) {
this.bzp = bzp;
}
@Override
public void run() {
while (true) {
bzp.setBaoZi("包子");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
3).“消费者”线程:
public class GetThread extends Thread {
private BaoZiPu bzp ;
public GetThread(BaoZiPu bzp) {
this.bzp = bzp;
}
@Override
public void run() {
while (true) {
String s = this.bzp.getBaoZi();
System.out.println(s);
}
}
}
4).测试类:
public class Demo {
public static void main(String[] args) {
//1.创建一个包子铺对象
BaoZiPu bzp = new BaoZiPu();
//2.分别创建生产者与消费者线程
SetThread setThread = new SetThread(bzp);
GetThread getThread = new GetThread(bzp);
setThread.start();
getThread.start();
}
}
04.第二章:线程池_线程池思想概述:
1).什么是“线程池”:就是封装了很多“线程对象”的一个“容器”。
2).为什么要用“线程池”:
1).一个Thread对象只能执行一次。如果再想执行,必须再次创建对象;而且创建一个Thread对象很耗时,而且很占用内存。
2).如果一个程序需要反复的、大量的使用同一个线程,就需要反复、大量的创建同一个线程对象,这样就使程序的运行效率降低。
3).“线程池”可以先期缓存一些“线程对象”,这些线程对象在使用后不会被销毁,如果再次需要,可以再次调用,这样就使得这些“线程对象”可以反复使用,从而提高程序的运行效率。
05.第二章:线程池_线程池概念:
1).Java提供了一个“线程池”的实现;从JDK1.5开始。
2).它可以缓存一些线程对象,并可以反复重用。
06.第二章:线程池_线程池的使用:
public class Demo {
public static void main(String[] args) throws InterruptedException {
//下面创建了两次对象,每次5秒,一共用时:10秒
/*MyThread t1 = new MyThread();//需要5秒
t1.start();
t1 = new MyThread();//需要5秒
t1.start();*/
MyThread t1 = new MyThread();//需要5秒
//使用线程池--能容纳2个线程的线程池对象
ExecutorService service = Executors.newFixedThreadPool(2);
//2.让线程池去执行,并缓存一个线程
service.submit(t1);//执行,并缓存这个线程;
System.out.println("主线程休息10秒:" );
Thread.sleep(1000 * 10);
System.out.println("主线程醒来,第二次执行开枪线程...");
service.submit(t1);
service.submit(t1);
service.submit(t1);
//关闭线程池
service.shutdown();
}
}
07.第三章:Lambda表达式_回顾面向接口编程及其优点:
public interface IUSB{
public void run();
}
public class Mouse implements IUSB{
public void run(){
System.out.println("鼠标开始工作...");
}
}
public class Keyboard implements IUSB{
public void run(){
System.out.println("键盘开始工作...");
}
}
public class Computer{
public void useUsb(IUSB m){//更多设备只需要实现IUSB接口即可,此类就可以不用更改。利于程序的扩展
m.run();
}
}
测试类:
main(){
Computer pc = new Computer();
pc.useUsb(new Mouse());
pc.useUsb(new Keyboard());
//匿名对象
pc.useUsb(new IUSB(){
public void run(){
System.out.println("手机可以插到电脑上了....");
}
});
}
08.第三章:Lambda表达式_回顾冗余的Runnable代码:
//2.需要一个线程:打印i
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100 ; i++) {
System.out.println("i = " + i);
}
}
}).start();
//3.还需要一个线程:打印k
new Thread(new Runnable() {
@Override
public void run() {
for (int k = 0; k < 100 ; k++) {
System.out.println("k = " + k);
}
}
}).start();
//4.需要一个线程:打印m
new Thread(new Runnable() {
@Override
public void run() {
for (int m = 0; m < 100 ; m++) {
System.out.println("m = " + m);
}
}
}).start();
09.第三章:Lambda表达式体验Lambda的更优写法示意图:
new Thread(()->{
for (int i = 0; i < 100 ; i++) {
System.out.println("i = " + i);
}
}).start();
new Thread(()->{
for (int k = 0; k < 100; k++) {
System.out.println("k = " + k);
}
}).start();
new Thread(()->{
for (int m = 0; m < 100; m++) {
System.out.println("m = " + m);
}
}).start();
匿名内部类和Lambda表达式的对应关系图:
10.第三章:Lambda表达式_编程思想转换及函数式编程思想概述:
1).编程思想的转换:
之前:要制作多个Runnable的匿名子类。
现在:只需要关注这些子类中具体要做什么,将要做的事情使用Lambda表达式传递个方法即可。
2).什么是“函数式编程”:
之前考虑传递的是“匿名子类的对象”。
现在考虑传递的是“做什么的函数(方法)”。
将“匿名子类对象”使用“没有名字的函数”来代替。
11.第三章:Lambda表达式Lambda的使用前提标准格式:
1).Lambda的使用前提:
1).Lambda代替的必须是一个“接口类型”;
2).接口中有且只有一个抽象方法(形参和返回值都可以有,可以无)
(接口中可以有默认方法、静态方法等)
2).标准格式:
1).一个小括号(形参列表)
2).一个箭头(->)
3).一段代码:(方法体--带大括号,有时可以不带大括号)
12.第三章:Lambda表达式练习使用Lambda的标准格式(无参无返回值):
1).public interface IAnimal{
public void eat();
}
public class Cat implements IAnimal{
public void eat(){
System.out.println("猫吃鱼...");
}
}
2).测试类:
main(){
public static void main(String[] args){
//1.自定义子类
show(new Cat());
//2.匿名子类
show(new IAnimal(){
public void eat(){
System.out.println("狗吃骨头...");
}
});
//3.使用Lambda
show(()->System.out.println("猪吃草..."));
show(()->System.out.println("羊吃草..."));
}
public static void show(IAnimal a){
a.eat();
}
}
13.第三章:Lambda表达式练习使用Lambda的标准格式(有参有返回值):
1).例一:自定义接口:
interface IA{
public int calc(int a, int b);
}
class Zi implements IA{
@Override
public int calc(int a, int b) {
return a + b;
}
}
public class Demo {
public static void main(String[] args) {
//1.使用子类
/*show(new Zi(), 10, 20);
//2.使用匿名对象
show(new IA() {
@Override
public int calc(int a, int b) {
return a * b;
}
}, 10, 20);*/
//3.使用Lambda
//加法
show((int a, int b) -> {return a + b; }, 10, 20);
//减法
show((int a,int b)->{return a - b;},10,20);
//乘法
show((int a, int b) -> { return a * b;}, 10, 20);
//除法
show((int a,int b)->{return a / b;},10,20);
}
public static void show(IA ia,int x,int y) {
System.out.println(ia.calc(x,y));
}
}
2).例二:类库的接口:
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public static void main(String[] args) {
ArrayList stuList = new ArrayList<>();
stuList.add(new Student("Jack",19));
stuList.add(new Student("Rose", 18));
stuList.add(new Student("Anna",20));
stuList.add(new Student("Rose",21));
stuList.add(new Student("Rose", 16));
Collections.sort(stuList,(Student o1,Student o2)->{return o1.getAge() - o2.getAge();});
System.out.println(stuList);
}
14.第三章:Lambda表达式练习使用Lambda的标准格式(有参无返回值):
Arrays.sort(T[] arr,Comparator cp)
interface IA{
public void show(int a, int b);
}
public class Demo {
public static void main(String[] args) {
//匿名内部类:
fun(new IA(){
public void show(int m,int n){
System.out.println(m + n);
},10,20);
//使用Lambda
fun((int m,int n)->{System.out.println(m + n);},10,20);
fun((int m,int n)->{System.out.println(m * n);},10,20);
}
public static void fun(IA a, int x, int y) {
a.show(x,y);
}
}
15.第三章:Lambda表达式_Lambda的省略格式及省略原则:
1).省略原则:
1).Lambda中形参列表的“数据类型”都可以省略(要省全省,否则全不省);
2).如果形参只有一个,数据类型和小括号可以省略(要省略小括号,必须省略数据类型);
3).如果大括号(方法体)只有一句话,
可以省略:return关键字、大括号、语句后的分号(要省就全省,要用就全用)
例如:有返回值:可以省略return、大括号、语句后的分号
Collections.sort(stuList,(o1,o2)->{return o1.getAge()-o2.getAge();});//完整语句
Collections.sort(stuList,(o1,o2)-> o1.getAge()-o2.getAge());//省略语句
例如:无返回值:可以省略:大括号、语句后的分号;
interface IAnimal{
public void eat();
}
public static void main(String[] args){
show(()->{System.out.println("猫吃鱼...");});//完整格式;
show(()->System.out.println("猫吃鱼..."));//省略格式
}
public static void show(IAnimal a){
a.eat();
}
总结:
01.能够理解线程通信概念
1).指多个线程共同完成一个任务的过程中,需要相互传递信息,相互协同,从而完整的完成同一个任务,这就需要线程间进行通信;
02.能够理解等待唤醒机制
1).等待和唤醒机制是线程间通信的一种形式;一个线程等待,另一个线程唤醒之前等待的线程;这就体现了两个线程在协作;
03.能够描述Java中线程池运行原理
1).就是缓存了大量“线程对象”的一个“容器”。容器中的“线程对象”都可以反复重用,从而提高程序的执行效率。
04.能够理解函数式编程相对于面向对象的优点
1).函数式编程是向方法中传递“一个函数”,不需要定义接口的子类,然后创建子类对象,并传到方法中,函数式编程关注的是:做什么,而不是以什么形式做,所以代码上看起来更简洁。
05.能够掌握Lambda表达式的标准格式
1).一对小括号;
2).一个箭头;
3).一对大括号(方法体)
06.能够使用Lambda标准格式使用Runnable与Comparator接口
1.Runnable:
new Thread(()->{System.out.println(“线程启动…”);}).start();
2.Comparator:
…
Collections.sort(stuList,(Student o1,Student o2)->{return o1.getAge()-o2.getAge();});
07.能够掌握Lambda表达式的省略格式与规则
1).形参类型都可以省略;
2).如果只有一个形参:可以省略:小括号和形参类型;
3).如果后面的大括号中只有一句代码:
有返回值的情况:可以省略:return、大括号、语句后的分号;
无返回值的情况:可以省略:大括号、语句分号;
08.能够使用Lambda省略格式使用Runnable与Comparator接口
1.Runnable:
new Thread(()->System.out.println(“线程启动…”)).start();
2.Comparator:
…
Collections.sort(stuList,(o1,o2)->o1.getAge()-o2.getAge());
09.能够通过Lambda的标准格式使用自定义的接口(有且仅有一个抽象方法)
interface IA{
public void show();
}
public static void main(String[] args){
fun(()->{System.out.println(“呵呵”);});
}
public static void fun(IA a){
a.show();
}
10.能够通过Lambda的省略格式使用自定义的接口(有且仅有一个抽象方法)
fun(()->System.out.println(“呵呵”));
11.能够明确Lambda的两项使用前提
1).必须是一个接口类型;
2).接口中必须只有一个抽象方法;(抽象方法必须能够上下文推断)