1.进程和线程概念
    进程:是程序的一次执行过程,是系统运行程序的基本单位,占有独立的内存空间
    线程:线程是进程中的一个执行单元,负责当前进程中程序的执行
    特点:一个应用程序可以有多个进程,一个进程可以有多个线程
    2.线程调度:
    分时调度:所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间。
    抢占式调度:优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性),Java使用的为抢占式调度
    3.thread类
    构造方法

    Thread() : 分配一个新的线程对象。
    Thread(String name) : 分配一个指定名字的新的线程对象。
    Thread(Runnable target) : 分配一个带有指定目标新的线程对象。
    Thread(Runnable target,String name) : 分配一个带有指定目标新的线程对象并指定名字。

    常用方法

    String getName() 获取当前线程名称。
    void start() 导致此线程开始执行; Java虚拟机调用此线程的run方法。
    void run() 此线程要执行的任务在此处定义代码。
    static void sleep(long millis) 使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。
    static Thread currentThread() 返回对当前正在执行的线程对象的引用。

    注意:sleep方法本身带有异常,需要处理异常
    4.创建线程类(方式一):
    a. 定义Thread类的子类,并重写该类的run()方法,该run()方法的方法体就代表了线程需要完成的任务,因此把run()方法称为线程执行体。
    b. 创建Thread子类的实例,即创建了线程对象
    c. 调用线程对象的start()方法来启动该线程
    例子:

    1. public class MyThread extends Thread {
    2. @Override
    3. public void run() {
    4. //代码
    5. }
    6. }

    start()方法会开辟一块新的栈空间,并在里面调用run()方法。
    5.创建线程(方法二):
    a. 定义Runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。
    b. 创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,该Thread对象才是真正 的线程对象。
    c. 调用线程对象的start()方法来启动线程。
    例子:

    1. public class MyRunnable implements Runnable{
    2. @Override
    3. public void run() {
    4. }
    5. }
    6. public class Demo {
    7. public static void main(String[] args) {
    8. MyRunnable mr = new MyRunnable();
    9. Thread t = new Thread(mr);
    10. t.start();
    11. }
    12. }

    区别:
    1.避免了单继承的局限性:实现Runnable接口之后还可以继承或者实现其他类和接口
    2.增强了程序的拓展性,降低程序的耦合性:实现Runnable接口的方式,把设置线程和开启线程的任务进行了分离(解耦)
    6 .匿名内部类:简化代码,将子类继承父类,重写父类的方法,创建子类对象合成一步(或者接口也一样)
    格式:
    new 父类/接口( ){
    重写父类/接口中的方法
    }.start();
    例子:

    1. Runnable r = new Runnable(){
    2. public void run(){
    3. }
    4. }
    5. new Thread(r).Start();
    6. //或者直接将new Rannable构造匿名类放入Thread构造参数中,一步到位

    7.线程同步
    同步代码块:synchronized关键字可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。
    格式:
    synchronized(同步锁对象){
    需要同步操作的代码
    }
    注意:
    a.锁对象可以是任意类型
    b.多个线程对象要使用同一把锁
    同步方法:
    格式:
    public synchronized void method(){
    可能会产生线程安全问题的代码
    }
    注意:同步方法中使用调用这个方法的类作为锁对象,也就是this。如果是静态同步方法,锁对象是RunnableImpl.class类
    Lock锁:
    方法:
    public void lock() 加同步锁
    public void unlock() 释放同步锁。
    格式:lock锁通过子类ReentrantLock创建对象来使用
    Lock lock=new ReentrantLock();
    使用:在关键代码之前上锁,在关键代码之后解锁
    注意:可以将解锁放到finally中,这样无论如何都会释放锁
    8.线程状态
    image.png
    9.线程池:其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源。
    格式:
    ExecutorService 线程池名 = Executors.newFixedThreadPool(线程数量)
    步骤:
    1. 创建线程池对象
    2. 创建Runnable接口子类对象
    3. 通过线程池对象的.submit(接口子对象)方法实现线程的取用和运行
    4. 关闭线程池(一般不做)
    9.Lambda表达式:做什么,而不是怎么做
    格式:(参数类型 参数名称) -> { 代码语句 }
    说明:仅仅保留最关键的参数和方法体
    省略规则:
    a. 小括号内参数的类型可以省略;
    b. 如果小括号内有且仅有一个参,则小括号可以省略;
    c. 如果大括号内有且仅有一个语句,则无论是否有返回值,都可以省略大括号、return关键字及语句分号。
    使用前提:
    a. 使用Lambda必须具有接口,且要求接口中有且仅有一个抽象方法。 无论是JDK内置的Runnable、Comparator接口还是自定义的接口,只有当接口中的抽象方法存在且唯一时,才可以使用Lambda。
    b. 使用Lambda必须具有上下文推断。 也就是方法的参数或局部变量类型必须为Lambda对应的接口类型,才能使用Lambda作为该接口的实例。