发表于: 2018-10-19 22:51:21
2 326
今天完成的事情:
1、学习lambda表达式
# Lambda表达式
Lambda表达式的主要作用是代替匿名内部类的繁琐语法
## Lambda表达式组成
Lambda表达式由三部分组成
+ 形参列表:形参列表允许省略形参类型,如果形参列表中只有一个参数,甚至连形参列表的圆括号也可省略。
+ 箭头(->)
+ 代码块: 若代码块只有一条语句,可省略代码块的花括号;当Lambda代码块只有一条return语句时,return可省。
## Lambda表达式与函数式接口
lambda表达式在实际运行中会被当做一个“任意类型”的对象。
lambda表达式的类型被称为“目标类型”,此目标类型必须是“函数式接口”。
(函数式接口表示只包含一个抽象方法的接口。函数式接口可以包含多个默认方法、类方法,但只能声明一个抽象方法)
## lambda表达式的两个限制
+ lambda表达式的目标类型必须是明确的函数式接口。
+ lambda表达式只能为函数式接口创建对象。
## lambda表达式3种常见使用方法
+ 将lambda表达式赋值给函数式接口类型的变量
+ 将lambda表达式作为函数式接口类型的变量
+ 使用函数式接口对lambda表达式进行强制类型转换
lambda表达式语法结构很简单,只由 形参列表 -> 代码块 三部分组成,其主要作用是代替匿名内部类,因为使用lambda表达式会更加简洁。下面是使用lambda表达式的一个例子
interface Eatable{
void taste();
}
interface Flyable{
void fly(String weather);
}
interface Addable{
int add(int a, int b);
}
public class LambdaQs {
// 调用该方法需要Eatable对象
public void eat(Eatable eatable){
System.out.println(eatable);
eatable.taste();
}
public void driver(Flyable flyable){
// System.out.println(flyable);
flyable.fly("sunny ...");
}
public void test(Addable addable){
System.out.println("相加和为:"+addable.add(2,3));
}
public static void main(String[] args){
LambdaQs lambdaQs = new LambdaQs();
// Lambda表达式的代码块只有一条语句,可以省略花括号
// eat(Eatable eatable) 这里的lambda表达式是为了代替Eatable的匿名实现类里面taste()方法里面的代码块。
lambdaQs.eat(()->System.out.println("香蕉好吃"));
// 整个lambda表达式为driver的参数,而weather为fly方法参数,代码块为fly方法的实现
lambdaQs.driver((weather)->{
System.out.println("大雨滂沱"+weather);
System.out.println("lalalala啊哈哈");
});
// lambda其实就是匿名类的一个实现
lambdaQs.test((a,b)->a+b);
}
}
2、学习多线程
# 多线程
# 1 线程概述
## 1.1 并发与并行
并行指在同一时刻,有多条指令在多个处理器上同时执行;
并发指在同一时刻只能有一条指令执行,但多个进程指令被快速轮换执行,使得宏观上具有多个进程同时执行的效果。
## 1.2 进程的特性
+ 独立性
+ 动态性
+ 并发性
## 1.3 线程与进程
线程是进程的执行单元。一个程序运行后至少有一个进程,一个进程至少包含一个线程。
# 2 线程的创建和启动
## 2.1 创建线程三种方式
+ 继承Thread类创建线程类
+ 实现Runnable接口创建线程类
二者区别:
1、前者直接创建的Thread子类即可代表线程对象;后者创建的Runnable对象只能作为线程对象的target。
2、后者创建的线程可以共享同一个线程类的实例变量。
+ 实现Callable接口创建线程类
## 2.2 线程方法
+ Thread.currentThrad(): 此方法是Thread类的静态方法,该方法总是返回当前正在执行的线程对象。
+ getName():Thread类实例方法,返回调用该方法的线程名字。
# 3 线程的生命周期
线程有 New新建、Runnable就绪、Running运行、Blocked阻塞、Dead死亡 五种状态。
## 3.1 新建状态
new 线程对象 --> 新建状态
## 3.2 就绪状态
线程对象.start() --> 就绪状态 (启动线程使用start方法,而不是run方法;只能对处于新建状态的线程调用start方法,否则引发IllegalThreadStateException异常)
## 3.3 运行状态
当处于就绪状态的线程获得了CPU,开始执行run方法的线程执行体,则此线程处于运行状态。
## 3.4 阻塞状态
## 3.5 死亡状态
线程以如下三种方式结束后就处于死亡状态:
+ run()或call()方法执行完成,线程正常结束
+ 线程抛出一个未捕获的Exception或Error
+ 直接调用该线程的stop()方法来结束线程(此方法易导致死锁)
创建线程有三种方式
(1)通过继承Thread类创建线程
public class ThreadDemo extends Thread{
private int i;
/**
* @Desciption: 重写run()方法,此方法的方法体就是线程执行体
* @Author: jk-leo
* @Date: 2018/10/19 15:23
*/
@Override
public void run(){
for (; i<100; i++){
// 当线程类继承Thread类时,直接使用this即可获得当前线程
// Thread对象的getName()返回当前线程的名字(当前线程指调用该方法的线程)
System.out.println("run方法中:"+this.getName() +" "+i);
}
}
public static void main(String[] args){
for (int i=0; i<100; i++){
// 调用Thread的currentThread()方法获取当前线程(这里的当前线程是主线程main)
System.out.println("主方法中: "+Thread.currentThread().getName()+" "+i);
if (i == 20){
// 创建并启动第一个线程
new ThreadDemo().start();
// 创建并启动第二个线程
new ThreadDemo().start();
}
}
}
}
(2)通过实现Runnable接口创建线程
public class RunnableDemo implements Runnable{
private int i;
// run()为线程执行体
@Override
public void run() {
for (; i<100; i++){
/*
* 当线程类实现Runnable接口时,如果想获取当前线程,只能使用
* Thread.currentThread()方法。
*/
System.out.println("run方法中:"+Thread.currentThread().getName() +" "+i);
}
}
public static void main(String[] args){
for (int i=0; i<100; i++){
System.out.println("main方法中:"+Thread.currentThread().getName()+" "+i);
if (i == 20){
RunnableDemo runnableDemo = new RunnableDemo();
// 通过new Thread(target, name) 方法创建新线程
new Thread(runnableDemo,"新线程1").start();
new Thread(runnableDemo,"新线程2").start();
}
}
}
}
(3)通过实现Callable接口创建进程
public class CallableDemo {
public static void main(String[] args){
// 创建Callable对象
CallableDemo callableDemo = new CallableDemo();
// 使用lambda表达式创建Callable<Integer>对象,这里对lambda表达式的目标类型进行了强转
FutureTask<Integer> task = new FutureTask<Integer>((Callable<Integer>)()->{
int i = 0;
for (; i<100; i++){
System.out.println(Thread.currentThread().getName()+" 的循环变量i的值为:"+i);
}
// call()方法可以有返回值
return i;
});
for (int i=0; i<100; i++){
System.out.println(Thread.currentThread().getName()+" 的循环变量i的值:"+i);
if (i == 20){
// 实质还是以Callable对象来创建并启动线程的
new Thread(task, "有返回值的线程").start();
}
}
// 获取线程返回值
try {
System.out.println("子线程的返回值:"+task.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
三种创建线程的方式对比
# 创建线程的三种方式对比
1、实现Runnable接口与实现Callable接口的方式基本相同,只是Callable接口定义的方法有返回值,可以声明抛出异常。二者可以归为一类
# 采用实现Runnable、Callable接口的方式创建多线程的优缺点
## 优点
+ 线程类只是实现了Runnable或Callable接口,所以还可以继承其他类
+ 多个线程可以共享一个target对象,非常适合多个相同线程来处理同一份资源的情况。
## 缺点
+ 编程复杂,若需要访问当前线程,则必须使用Thread.currentThread()方法
# 采用继承Thread类的方式创建多线程的优缺点
## 优点
+ 编写简单,若需访问当前线程,无需使用Thread.currentThread()方法,直接使用this即可获得当前线程。
## 缺点
+ 因为已经继承了Thread类,所以不能再继承其他父类
# 总结:一般推荐采用实现Runnable接口、Callable接口的方式来创建多线程
遇到的问题:
无
收获:
了解了lambda表达式,接触了多线程
明天计划的事情:
将多线程看完
评论