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 @   Schieber  阅读(133)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示
主题色彩