Loading

Java 多线程学习笔记

多线程

在单个程序中同时运行多个线程完成不同的工作,称为多线程(提升整体处理性能)

一. 什么是线程?

线程是程序的最小单位,相对独立的可调用单元,是 CPU 最小基本单位;

在同一个程序中不同的线程完成功能,称为多线程。(软件中最小单位就是线程)

二. 线程、进程、程序的关系(☆)

程序 进程 线程
程序就是一段静态的代码,是应用程序的蓝本 进程是正在运行的程序的实例:进程是程序的一次正常运行,从代码加载到最后一句代码的执行,整个过程就是进程的生命周期 进程中独立、可调用的最小执行单元:线程是程序中一个单一的顺序控制流程
  • 程序与进程的关系:
    一个程序一般只有一个进程,但一个程序可以拥有多个进程
    一个进程只能属于一个程序

  • 进程与线程的关系:
    一个进程拥有多个线程,一个线程只能属于一个进程
    一个程序只有一个主线程

一个程序只有一个主线程:Java 应用程序中主线程就是main方法,其他的都是子线程

三. 线程的创建

  1. 创建一个类继承 Thread 类(多个线程分别完成自己的任务)

    Thread th = new Thread();
    th.start();
    
  2. 创建一个类实现一个 Runnable (多个线程共同完成同一个任务)

    Thread th = new Thread(new Runnable());
    th.start();
    

使用 Runnable 接口创建的线程,还是要借用 Thread 类来启动线程

线程是异步的,可以同时操作多个任务

四. 线程的生命周期(☆)

  1. 创建:线程的构造

  2. 启动:线程对象调用start()方法

  3. 运行:占用CPU,进入run()方法

  4. 中断:在run()方法中,遇到sleep()wait()方法,线程就会中断,让出CPU资源

  5. 死亡:运行完run()方法

五. 线程的状态(☆)

  1. 新建状态(NEW):创建了一个线程对象,但是没有启动

  2. 就绪状态(RUNNABLE):线程对象调用了start()方法

  3. 运行状态(RUNNABLE):线程对象占用CPU,进入run()方法

  4. 阻塞状态(BLOCKED):线程对象放弃CPU,暂停运行,遇到sleep()方法

  5. 死亡状态(TERMINATED):线程运行完run()方法

六. 线程的休眠(sleep)与唤醒(interrupt)

当一个线程对象在 sleep 的时候,可以用过interrupt()方法强制唤醒,唤醒后会抛出java.lang.InterruptedException

七. 线程常用方法

方法 描述
start() 启动线程(使线程处于就绪状态)
run() 线程占用CPU正在运行,业务逻辑写在此方法中
setName() 给线程设置名称
getName() 获取线程名称
setPriority() 设置线程的优先级别:1为最小、5为默认、10为最大
getPriority() 获取线程的优先级
currentThread() 获取当前正在运行的线程
getState() 获取线程状态
sleep() 线程的休眠
interrupt() 线程中断休眠
isInterrupted() 判断线程是否为中断状态
isAlive() 测试线程是否处于活动状态
setDaemon() 把线程设置为守护线程(当程序中其他守护线程结束时,该守护线程也会结束)
isDaemon() 判断线程是否为守护线程
join() 等待该线程终止
yield() 暂停当前正在执行的线程,并执行其他线程(包含了自己本身)

八. 线程的同步

  1. 什么是线程不安全?

    多个线程改变同一个对象的同一个全局属性,就会造成线程不安全

  2. 线程不安全有三个必要条件?

    1. 必须是同一个对象

    2. 必须改变同一个全局属性

    3. 必须是多个线程操作

  3. 同步锁

    1. 在方法行增加 synchronized 关键字,增加同步关键字之后,方法调用变缓慢,变成重量级

    2. 同步方法(方法锁):在方法上面加 synchronized 关键字

    3. 同步代码块(对象锁):锁相对应的对象

    4. 类锁:synchronized(Student.class){}

    5. 可重入锁(ReentrantLock):锁具体的代码块

九. 线程的挂起(wait)与恢复(notifyAll)

wait():线程挂起

notify():唤醒单个线程

notifyAll():唤醒所有线程

wait()方法不稳定必须要加上同步锁
以上三个方法全是 Object 类的方法

十. 单例模式(自始至终产生一个对象)(☆)

  1. 懒汉模式

    1. 构造私有化
      1. 声明一个静态的自身对象属性

      2. 提供静态方法,返回自身对象,方法必须加上synchronized关键字

  2. 恶汉模式

    1. 构造私有化
      1. 声明一个静态自身属性,并且实例化

      2. 提供一个静态方法返回自身对象

作用 优点 缺点
始终保持一个实例 节约内存空间,创建效率高 容易造成线程不安全问题

十一. 枚举

枚举是 Java 中一种数据类型,相当于常量,但比常量的扩展性强
枚举类型存放在 JVM 的常量池中,永远不会被回收,除非程序关闭
枚举默认是单例,所以构造方法必须私有化
声明枚举的时候,必须固定好实例,枚举的实例必须事先声明

定义:
public enum 枚举名称{}

十二. 同步锁(sysnchronized)使用事项 (☆)

  1. 动态方法上的 synchronized 锁,锁的是当前对象

  2. 静态方法上的 synchronized 锁,锁的是当前类的字节码

  3. 动态方法与静态方法进行同步锁,那么锁同一个全局变量

  4. 同步方法中调用了wait()方法,会让出 CPU 并且释放锁,调用sleep()方法,只会让出 CPU 不会释放锁

  5. 同步锁必须锁同一样东西才会生效

十三. sleep 与 wait 区别 (☆)

  1. sleep 是 Thread 类中的方法,wait 方法是 Object 类的方法

  2. sleep 方法只会让出 CPU,不会释放锁

  3. wait 方法会让出 CPU 并且释放锁

  4. 使用 sleep 方法不需要结合同步锁,wait 方法一定要结合同步锁使用

  5. sleep 方法会根据参数设置的时间自然醒,wait 方法除了会根据参数设置的时间自然醒,还可以通过notify()notifyAll()唤醒

十四. 定时任务

Timer:定时器
TimerTask:定时器任务

十五. 线程同步方式

  1. synchronized 关键字修饰的方法

  2. synchronized 关键字修饰的语句块

  3. volatile 关键字修饰的变量,多个变量访问时,可以保证最新值

  4. JDK 在java.util.concurrent包下提供了一把锁的机制,代码如下:

    // 可以放在任何地方进行同步锁
    Lock lock = new ReentrantLock();
    // 加锁
    lock.lock()
    // 解锁
    lock.unlock()
    
  5. 使用 ThreadLocal 管理全局变量,可以使单例对象多例属性,也称为:线程变量。
    ThreadLocal通过set方法进行赋值,get方法取值

  6. 使用队列阻塞

  7. 使用原子变量实现线程同步

十六. 线程安全集合与线程不安全集合

线程安全 线程不安全
StringBuffer StringBuilder
Vector ArrayList
HashTable HashMap

作业

  1. 做一个简单的缓存机制,缓存中存储部分表的数据,使用数据时从内存中获取,不去查数据库
    1. 程序运行main方法时,把指定表的数据读取出来,存放到单例模式中的数据结构中(map)

    2. 查询数据时,直接从单例模式中获取表中的数据

    3. 每隔半小时,同步一次数据库与内存中的数据

什么样的数据适合放在缓存机制中?

  1. 经常被查询的数据
  2. 不会经常改变的数据,更新的频率不频繁
posted @ 2022-02-21 22:09  Schieber  阅读(132)  评论(0编辑  收藏  举报