发表于: 2018-10-19 22:51:21

2 328


今天完成的事情:

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的参数,而weatherfly方法参数,代码块为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()方法执行完成,线程正常结束
+ 线程抛出一个未捕获的ExceptionError
+ 直接调用该线程的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++){
        // 调用ThreadcurrentThread()方法获取当前线程(这里的当前线程是主线程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接口定义的方法有返回值,可以声明抛出异常。二者可以归为一类

# 采用实现RunnableCallable接口的方式创建多线程的优缺点
## 优点
+ 线程类只是实现了RunnableCallable接口,所以还可以继承其他类
+ 多个线程可以共享一个target对象,非常适合多个相同线程来处理同一份资源的情况。
## 缺点
+ 编程复杂,若需要访问当前线程,则必须使用Thread.currentThread()方法
# 采用继承Thread类的方式创建多线程的优缺点
## 优点
+ 编写简单,若需访问当前线程,无需使用Thread.currentThread()方法,直接使用this即可获得当前线程。
## 缺点
+ 因为已经继承了Thread类,所以不能再继承其他父类

# 总结:一般推荐采用实现Runnable接口、Callable接口的方式来创建多线程 

 


遇到的问题:


收获:

了解了lambda表达式,接触了多线程


明天计划的事情:

将多线程看完



返回列表 返回列表
评论

    分享到