1. 线程简介:程序、进程、线程
  2. 线程实现:继承Thread类、实现Runnable接口、实现Callable接口
  3. 线程状态
  4. 线程同步
  5. 线程通信问题
  6. 高级主题

📌概念简介

  1. 程序:指令和数据的有序集合
  2. 进程:程序的一次执行过程,他是一个动态的概念,是系统资源分配和调度的基本单位(虚拟存储空间、文件描述符等)。可以把进程理解为在操作系统中运行的程序,比如你的QQ、播放器。
  3. 线程:是进程的一个执行单元。通常一个进程中包含若干个线程,一个进程中至少一个线程(主线程、GC线程),不然没有存在的意义,线程是CPU调度和执行的单位。每个线程都有各自的线程栈、自己的寄存器环境、自己的线程本地存储。
  4. 主线程与子线程:JVM启动时会创建一个主线程,该主线程负责执行main方法。如果在A线程中创建了B线程,则称B线程为A线程的子线程,相应的A线程为B线程的父线程。
  5. 串行并发(Concurrent)与并行(Parallel):串行是以任务依次执行,并发在任意时刻只能有一条指令执行,但多个进程指令快速轮转执行(因此每个线程拥有各自的线程栈,自己的寄存器环境和本地存储等少量资源),并行是指同一时刻多条指令在多核上执行。
  6. 在一个进程中,如果开辟了多个线程,线程的运行有调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能人为干预的
  7. 对同一个资源操作时,会存在资源抢夺的问题,需要加入并发控制
  8. 线程会带来额外的开销,如CPU调度时间,并发控制开销
  9. 每个线程在自己的工作内存交互,内存控制不当会造成数据不一致

📌线程创建

  1. 继承Thread类
  2. 实现Runnable接口
  3. 实现Callable接口

    Callable的好处

    1. 可以定义返回值
    2. 可以抛出异常
  1. package com.pai.class02;
  2. import java.util.concurrent.*;
  3. //Callable实现
  4. public class TestThread5 implements Callable<Boolean> {
  5. @Override
  6. public Boolean call() throws Exception {
  7. System.out.println(Thread.currentThread().getName());
  8. return true;
  9. }
  10. public static void main(String[] args) throws ExecutionException, InterruptedException {
  11. TestThread5 t1 = new TestThread5();
  12. TestThread5 t2 = new TestThread5();
  13. TestThread5 t3 = new TestThread5();
  14. ExecutorService executorService = Executors.newFixedThreadPool(3);
  15. Future<Boolean> submit1 = executorService.submit(t1);
  16. Future<Boolean> submit2 = executorService.submit(t2);
  17. Future<Boolean> submit3 = executorService.submit(t3);
  18. Boolean rs1 = submit1.get();
  19. Boolean rs2 = submit2.get();
  20. Boolean rs3 = submit3.get();
  21. executorService.shutdown();
  22. }
  23. }
  1. 线程开启

    1. 启动线程是调用线程的start()方法,实质是请求JVM运行相应的线程,这个线程具体在什么时候运行由线程调度器(Scheduler)决定。
    2. start调用并不意味着线程执行,只是在告诉JVM线程就绪,什么时候调度由线程调度器决定。
    3. 如果开启了开启了多个线程,start()的调用顺序并不意味着线程的启动顺序
    4. 当然如果是只有在A指令执行完毕后才调用B线程的start()方法,那么A指令的执行一定在B线程的前面
  2. run()和start()的区别

image.png
image.png

  1. this和Thread.currentThread()的区别

📌线程状态

image.png

  1. 什么情况下会进入就绪状态?

    📌线程方法

    image.png

    📌线程同步

    三大线程不安全案例

    📌死锁

    📌线程通信

    生产者-消费者问题

    管程法

    信号灯法

    📌线程池

    Thread的实现原理

    Thread的实现采用了静态代理模式。
    静态代理模式:真实对象和代理对象都要实现同一个接口,代理对象要代理真实角色 ```java package com.pai.class02;

public class TestStaticProxy { public static void main(String[] args) { WeddingCompany weddingCompany = new WeddingCompany(new You()); weddingCompany.happyMerry();

  1. //与Thread的对比
  2. Thread thread = new Thread(new Runnable() {
  3. @Override
  4. public void run() {
  5. System.out.println("静态代理");
  6. }
  7. });
  8. thread.start();
  9. }

} class You implements Merry{ @Override public void happyMerry() { System.out.println(“我要结婚”); } } class WeddingCompany implements Merry{ private You you;

public WeddingCompany(You you) {
    this.you = you;
}

@Override
public void happyMerry() {
    System.out.println("准备请柬");
    you.happyMerry();
    System.out.println("收红包");
}

} interface Merry{ void happyMerry(); }

总结:Thread是静态代理对象,实现了Runnable接口的类是被代理对象。
<a name="70uHF"></a>
# 补充——Lambda表达式
<a name="LuNuo"></a>
## 为什么使用lambda表达式?

1. 避免匿名内部类定义过多
1. 可以让你的代码看起来简洁
1. 去掉了一堆没有意义的代码,只留下核心逻辑
<a name="keL3Y"></a>
## 函数式接口
任何接口秒如果只包含唯一的抽象方法,那么他就是一个函数式接口,如下:
```java
public interface Runnable{
    public abstract void run();
}

对于函数式接口,我们可以通过lambda表达式

实例

package com.pai.class02;

//lambda表达式
public class TestLambda1 {

    //3. 静态内部类
    static class Like2 implements ILike{
        @Override
        public void lambda() {
            System.out.println("静态内部类");
        }
    }



    public static void main(String[] args) {
        ILike like = null;
        like = new Like1();
        like.lambda();

        like = new Like2();
        like.lambda();

        //4. 局部内部类
        class Like3 implements ILike{
            @Override
            public void lambda() {
                System.out.println("局部内部类");
            }
        }
        like = new Like3();
        like.lambda();

        //5. 匿名内部类

        like = new ILike() {
            @Override
            public void lambda() {
                System.out.println("匿名内部类");
            }
        };
        like.lambda();

        //6. lambda表达式
        like = ()->{
            System.out.println("lambda表达式");
        };
        like.lambda();
    }
}

//1. 定义一个函数式接口
interface ILike{
    void lambda();
}
//2. 定义一个类实现该接口
class Like1 implements ILike{

    @Override
    public void lambda() {
        System.out.println("外部实现类");
    }
}

补充——守护线程

线程分为用户线程守护线程
虚拟机必须确保用户线程执行完毕。
虚拟机不必等待守护线程执行完毕,如后台记录操作日志,监控内存,垃圾回收等待机制