资讯动态

javaEE(2)多线程初阶

发布时间:2026/9/24 13:18:02 来源:尧图企业网站定制
1 线程的核心概念1.1 进程与线程的定义进程是操作系统进行资源分配的最小单位一个正在运行的应用程序对应一个独立进程拥有独立的内存地址空间。线程是操作系统进行任务调度的最小单位是进程内部的一条独立执行流。一个进程至少包含一个主线程同一进程内的多个线程共享进程的内存资源与文件资源。1.2 进程与线程的核心差异对比维度进程线程资源定位系统分配资源的最小单位系统调度 CPU 执行的最小单位内存空间进程间内存相互隔离独立寻址同一进程内线程共享堆内存与方法区各线程私有栈空间与程序计数器故障影响单个进程崩溃不影响其他进程单个线程异常可能导致整个进程终止调度开销创建、销毁、上下文切换开销较高创建、销毁、切换开销远低于进程1.3 Java线程与操作系统线程的关系线程是操作系统内核提供的原生能力Java 标准库中的java.lang.Thread类是对操作系统线程 API 的抽象与封装。调用线程对象的start()方法才会通过操作系统内核创建并启动一条原生线程重写run()方法仅用于定义线程的执行逻辑直接调用run()不会创建新线程代码仍在当前调用线程中串行执行。2 线程的创建方式2.1 继承Thread类通过继承Thread类并重写run()方法定义线程任务创建子类实例后调用start()启动线程。该方式受 Java 单继承机制限制适用于线程类无需继承其他父类的场景。classCustomThreadextendsThread{Overridepublicvoidrun(){System.out.println(Thread.currentThread().getName() 执行中);}}publicclassThreadCreateDemo1{publicstaticvoidmain(String[]args){CustomThreadthreadnewCustomThread();thread.start();}}2.2 实现Runnable接口通过实现Runnable接口定义任务逻辑再将任务实例传入Thread构造方法。该方式将任务定义与线程控制解耦支持类继承其他父类是更推荐的实现方式。classCustomTaskimplementsRunnable{Overridepublicvoidrun(){System.out.println(Thread.currentThread().getName() 执行中);}}publicclassThreadCreateDemo2{publicstaticvoidmain(String[]args){ThreadthreadnewThread(newCustomTask());thread.start();}}2.3 匿名内部类实现对于一次性使用的线程任务可通过匿名内部类快速创建无需单独定义实现类。publicclassThreadCreateDemo3{publicstaticvoidmain(String[]args){// 继承Thread的匿名内部类Threadt1newThread(){Overridepublicvoidrun(){System.out.println(匿名Thread实现);}};t1.start();// 实现Runnable的匿名内部类Threadt2newThread(newRunnable(){Overridepublicvoidrun(){System.out.println(匿名Runnable实现);}});t2.start();}}2.4 Lambda 表达式实现Runnable为函数式接口可通过 Lambda 表达式简化代码是实际开发中最常用的简洁写法。publicclassThreadCreateDemo4{publicstaticvoidmain(String[]args){ThreadthreadnewThread(()-System.out.println(Lambda方式创建线程));thread.start();}}3 Thread类核心API3.1 线程基础属性方法功能描述long getId()返回线程的唯一标识 IDString getName()返回线程名称主要用于日志调试Thread.State getState()返回线程当前的生命周期状态int getPriority()返回线程优先级优先级仅作为调度参考不保证执行顺序boolean isDaemon()判断是否为守护线程JVM 会在所有非守护线程终止后退出boolean isAlive()判断线程是否处于存活状态NEW 与 TERMINATED 状态返回 falseboolean isInterrupted()判断线程是否被设置中断标记调用后不清除标记3.2 线程休眠sleep()Thread.sleep(long millis)为静态方法使当前线程进入限时等待状态暂停执行指定时长。该方法不释放持有的锁且实际休眠时长大于等于参数设定值具体恢复时间由操作系统调度决定。3.3 线程等待join()join()方法使当前调用线程阻塞直到目标线程执行完毕后再继续执行用于协调多线程的执行顺序。publicclassJoinDemo{publicstaticvoidmain(String[]args)throwsInterruptedException{ThreadtasknewThread(()-{// 任务逻辑});task.start();task.join();// 主线程等待task执行完成}}3.4 线程中断机制Java 采用协作式中断机制通过设置中断标记通知线程终止而非强制抢占式终止。自定义标记位通过volatile修饰的布尔变量作为退出标志线程循环判断该标记决定是否终止。interrupt() 方法调用线程对象的interrupt()方法设置中断标记。若线程处于sleep/wait/join阻塞状态会抛出InterruptedException并清除标记若线程处于运行状态仅设置标记需通过Thread.currentThread().isInterrupted()主动检测。4 线程状态与流转线程的生命周期由Thread.State枚举定义共包含六种状态。4.1 六种状态定义状态定义NEW线程对象已创建尚未调用start()方法RUNNABLE可运行状态包含正在 CPU 执行与就绪等待调度两种子状态BLOCKED阻塞状态线程等待获取 synchronized 锁WAITING无限等待状态需由其他线程主动唤醒TIMED_WAITING限时等待状态达到指定时长后自动唤醒TERMINATED终止状态线程执行逻辑已完成4.2 状态流转逻辑调用start()后线程从 NEW 进入 RUNNABLE 状态。线程尝试获取锁失败时进入 BLOCKED 状态获取锁后回到 RUNNABLE。调用wait()、无超时join()时线程释放锁并进入 WAITING 状态被唤醒后重新竞争锁成功后回到 RUNNABLE。调用sleep()、带超时wait()/join()时线程进入 TIMED_WAITING 状态超时或被唤醒后回到 RUNNABLE。线程执行完毕后进入 TERMINATED 状态。5 线程安全问题分析5.1 线程安全的定义在多线程并发执行环境下程序运行结果与单线程串行执行的预期结果一致则称该程序是线程安全的。5.2 线程不安全的核心成因1原子性缺失原子性指一段操作要么完整执行要么完全不执行执行过程不会被其他线程打断。Java 中看似原子的代码如count实际包含“读内存-计算-写回内存”三步操作。多线程抢占式调度下操作中途可能被切换导致共享数据修改异常。2内存可见性问题Java 内存模型JMM规定所有共享变量存储于主内存每个线程拥有独立的工作内存对应 CPU 寄存器与高速缓存。线程操作共享变量时先从主内存拷贝副本到工作内存修改后再同步回主内存。由于线程工作内存的存在一个线程对共享变量的修改可能无法立即被其他线程感知导致数据不一致。3指令重排序编译器与 CPU 为优化性能会在不改变单线程语义的前提下调整指令执行顺序。在多线程场景下指令重排序可能导致跨线程逻辑不一致。6 线程安全的基础解决方案6.1 synchronized 关键字synchronized即监视器锁是 Java 内置的互斥同步机制能够保证原子性、内存可见性并禁止部分指令重排序。核心特性互斥性同一时刻仅一个线程能获取指定对象的锁进入同步代码块其他尝试获取同一锁的线程会阻塞等待。锁状态存储于 Java 对象头中。可重入性同一线程可重复获取同一把锁不会出现自身死锁。锁内部维护持有者线程与计数器每加锁一次计数器递增解锁时递减计数器归零时锁真正释放。三种使用形式publicclassSyncDemo{privatefinalObjectlockernewObject();// 1. 修饰代码块指定锁对象publicvoidmethod1(){synchronized(locker){// 同步逻辑}}// 2. 修饰普通方法锁对象为当前实例thispublicsynchronizedvoidmethod2(){// 同步逻辑}// 3. 修饰静态方法锁对象为当前类的Class对象publicstaticsynchronizedvoidmethod3(){// 同步逻辑}}标准库中的线程安全类线程不安全类ArrayList、HashMap、HashSet、StringBuilder线程安全类StringBuffer、Vector、Hashtable高并发场景推荐使用ConcurrentHashMap6.2 volatile 关键字volatile是轻量级同步机制仅作用于变量能够保证内存可见性与禁止指令重排序但不保证原子性。作用机制写 volatile 变量时强制将工作内存中的修改立即刷新回主内存。读 volatile 变量时强制从主内存读取最新值绕过线程工作内存缓存。适用场景与局限性适用于一写多读的场景如状态标记位。不适用于 count 等需要原子性的复合操作此类场景仍需通过锁机制保证线程安全。7 线程间协作wait/notify 机制wait()、notify()、notifyAll()是Object类的原生方法用于实现线程间的等待-唤醒协作必须在同步代码块中以锁对象调用。7.1 核心方法语义方法语义wait()当前线程释放锁进入对象的等待队列无限期等待唤醒wait(long timeout)限时等待超时后自动唤醒notify()随机唤醒等待队列中的一个线程调用后不会立即释放锁退出同步块后锁才释放notifyAll()唤醒等待队列中所有线程唤醒后所有线程重新竞争锁需注意wait()应置于循环中调用避免虚假唤醒导致逻辑异常。7.2 wait 与 sleep 的差异对比维度wait()sleep()所属类Object类方法Thread类静态方法锁要求必须在同步块中调用无需持有锁锁行为调用后释放持有的锁调用后不释放锁用途线程间协作通信单纯使线程暂停执行8 多线程经典应用场景8.1 单例模式单例模式保证一个类在程序运行期间仅存在一个实例。饿汉式实现类加载时即创建实例实现简单且天然线程安全缺点是类加载即初始化可能造成资源浪费。classSingletonHungry{privatestaticfinalSingletonHungryINSTANCEnewSingletonHungry();privateSingletonHungry(){}publicstaticSingletonHungrygetInstance(){returnINSTANCE;}}双重校验锁懒汉式实现首次调用时才创建实例通过双重 if 判断降低锁竞争结合volatile禁止指令重排序兼顾线程安全与性能。classSingletonLazy{privatestaticvolatileSingletonLazyinstancenull;privateSingletonLazy(){}publicstaticSingletonLazygetInstance(){if(instancenull){synchronized(SingletonLazy.class){if(instancenull){instancenewSingletonLazy();}}}returninstance;}}8.2 阻塞队列与生产者消费者模型阻塞队列是线程安全的队列结构遵循先进先出原则队列满时入队操作阻塞队列空时出队操作阻塞。阻塞队列是生产者消费者模型的核心实现组件通过队列解耦生产者与消费者平衡两者处理能力实现削峰填谷。Java 标准库提供BlockingQueue接口常用实现为LinkedBlockingQueue核心方法为put()阻塞入队与take()阻塞出队。importjava.util.concurrent.BlockingQueue;importjava.util.concurrent.LinkedBlockingQueue;publicclassProducerConsumer{publicstaticvoidmain(String[]args){BlockingQueueIntegerqueuenewLinkedBlockingQueue();ThreadproducernewThread(()-{while(true){intnum(int)(Math.random()*1000);try{queue.put(num);Thread.sleep(1000);}catch(InterruptedExceptione){e.printStackTrace();}}},生产者);ThreadconsumernewThread(()-{while(true){try{queue.take();}catch(InterruptedExceptione){e.printStackTrace();}}},消费者);producer.start();consumer.start();}}8.3 线程池核心价值频繁创建与销毁线程会产生较高开销。线程池通过复用一组已创建的线程执行任务降低线程生命周期开销提升系统响应速度。Executors工具类Executors提供线程池快速创建方法newFixedThreadPool(int n)创建固定线程数的线程池newCachedThreadPool()创建线程数动态增长的线程池newSingleThreadExecutor()创建单线程线程池newScheduledThreadPool(int n)创建支持定时任务的线程池ThreadPoolExecutor核心参数生产环境推荐手动创建ThreadPoolExecutor自定义核心参数corePoolSize核心线程数常驻线程数量maximumPoolSize最大线程数核心线程与临时线程总数上限keepAliveTime临时线程空闲存活时长workQueue存放待执行任务的阻塞队列threadFactory线程创建工厂RejectedExecutionHandler任务拒绝策略包含抛出异常、调用者执行、丢弃最旧任务、丢弃新任务四种实现。9 线程安全设计思路无共享设计线程使用私有局部变量从根源避免数据竞争。只读设计共享变量仅进行读操作天然线程安全。同步控制复合操作通过synchronized或显式锁保证原子性状态标记通过volatile保证内存可见性优先使用JDK内置并发工具类避免手动实现复杂同步逻辑。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价