java-线程和进程

发布时间:2026/10/31 6:41:54
java-线程和进程 1.什么是线程线程线程是操作系统能够进行运算调度的最小单位它被包含在进程之中是进程中的实际运作单位。进程就是一个独立程序像一个公司拥有独立内存不能互相共享资源。线程就是进程里的执行单元像公司里的员工。同一进程内的线程堆内存、方法区共享可以共享数据栈内存独立每个线程有自己的栈启动多个线程 开多个栈 同时执行 多线程并发。多线程的目的就是提高程序效率1、你敲java HelloWorld回车后发生了什么java HelloWorld这个命令一执行操作系统先启动 JVMJVM 本身就是电脑里的一个独立进程。进程可以简单理解成正在运行的程序电脑打开的软件都是进程。2、JVM 启动后立刻开 2 个线程进程里面可以包含多个线程线程就是进程里干活的执行单元。你写的 Java 程序只要运行天生最少自带 2 个线程线程 1主线程main 线程作用专门运行你代码里的main方法你所有写的业务代码、顺序执行的代码全部在主线程里跑程序入口public static void main就是主线程的入口方法线程 2垃圾回收线程GC 线程Java 独有的后台守护线程作用全程在后台默默运行自动回收没用的对象内存不用你手动管内存释放它一直盯着垃圾自动清掉3、重点什么叫「并发」这两个线程同时在运行互不耽误主线程在认认真真执行你的代码GC 垃圾回收线程在后台偷偷清理内存它们交替抢占 CPU看起来就是同时工作这就叫并发。2.什么是多线程多线程是java中的一种并发编程技术允许程序同时执行多个任务。每个线程代表一个独立的执行路径共享进程的资源如内存但拥有独立的栈空间。多线程可以提高程序效率尤其在处理I/O密集型或CPU密集型任务时。多线程的实现方式继承Thread类通过继承Thread类并重写run()方法实现线程逻辑。class MyThread extends Thread { Override public void run() { System.out.println(Thread running); } } // 启动线程 MyThread thread new MyThread(); thread.start();实现Runnable接口更推荐的方式避免单继承限制适合资源共享。class MyRunnable implements Runnable { Override public void run() { System.out.println(Runnable running); } } // 启动线程 Thread thread new Thread(new MyRunnable()); thread.start();单继承限制Java 类只能单继承继承Thread后就无法继承其他类实现Runnable是接口实现不占用继承名额类还可以继承别的父类灵活度更高。线程创建和业务代码分开Thread只负责开启线程Runnable只写业务代码耦合更低。实现Callable接口支持返回结果和抛出异常通常与FutureTask配合使用。class MyCallable implements CallableString { Override public String call() throws Exception { return Callable result; } } // 使用FutureTask获取结果 FutureTaskString task new FutureTask(new MyCallable()); new Thread(task).start(); System.out.println(task.get()); // 输出结果3.线程的生命周期新建New线程对象创建但未启动。就绪Runnable调用start()后线程等待CPU调度。运行Running线程获得CPU资源执行run()方法。阻塞Blocked线程因等待锁、I/O等操作暂停执行。终止Terminatedrun()方法执行完毕或异常终止。逐个详细讲解每个状态 含义 什么时候处于这状态1. NEW 新建状态new Thread()代码里刚new出线程对象还没调用 start ()只是在堆里创建了对象线程根本没启动没有栈内存操作系统还不认识这个线程2. RUNNABLE 就绪 运行状态调用thread.start()之后进入此状态。Java 把就绪、运行合并成这一个状态。就绪线程已经准备好抢到 CPU 时间片就能跑运行正在 CPU 上执行run()方法里的代码压栈、弹栈全部发生在这个状态run 方法调用 → 压栈run 内方法执行完弹栈。3. BLOCKED 阻塞状态锁阻塞线程想要获取synchronized 锁但是锁被别的线程抢走了只能在门外等着不能占用 CPU等别的线程释放锁它抢到锁就回到 RUNNABLE4. WAITING 无限等待无时间等待调用这些方法进入Object.wait()无参线程主动停下无限等待不占用 CPU不干活必须别人唤醒notify()/notifyAll()才能回到 RUNNABLE5. TIMED_WAITING 限时等待有时间等待调用这些方法进入Thread.sleep(毫秒)、Object.wait(时间)线程等待指定时间时间一到自动醒来回到 RUNNABLE日常用的最多的就是sleep()6. TERMINATED 终止死亡状态线程彻底结束生命周期走完进入条件run()方法全部执行完毕正常结束线程被异常终止一旦死亡不能再次 start () 重启线程一次性的。new Thread()只是在堆里创建了线程对象线程还没活没有栈属于NEW新建状态。调用t.start()之后JVM 底层做 3 件事① 给该线程开辟独立的栈内存② 线程状态变为RUNNABLE就绪③CPU 调度到它时自动调用run()方法重点start()本身不直接运行代码它只是激活线程真正执行业务代码的是run()。需要注意点使用了多线程机制之后main方法结束可能程序不会结束深度原理分析main方法 主线程程序启动时 JVM 创建的主线程入口就是main方法。main方法代码执行完、return 结束 →主线程死亡、主栈清空。但是JVM 什么时候关闭JVM 退出的条件所有的非守护线程全部死亡JVM 才会结束只要还有任意一个普通线程在运行哪怕主线程没了整个程序依然活着。其他自定义线程每个都有自己独立的栈主线程栈空了、结束了别的线程的栈依然在正常压栈、弹栈、运行代码互不影响3、通俗比喻结合你公司员工比喻JVM 公司主线程 老板其他子线程 员工main方法结束老板下班走了但是公司里的员工还在干活、上班 →公司不会关门只有所有员工全部下班公司才会关闭JVM 退出。代码示例public class Test { public static void main(String[] args) { // 这是主线程运行的代码 // 开启一个新的子线程分支线程 new Thread(() - { // 这里的代码 属于 子线程 while(true){ // 死循环永远一直跑停不下来 } }).start(); // 启动子线程 // 下面这句还是主线程的代码 System.out.println(主线程结束了); // main方法执行完毕 → 主线程死亡 } }2、这段代码运行时发生了什么① 程序启动 → JVM 创建主线程运行main方法主线程开始跑。② 主线程执行到new Thread(...).start()JVM 又创建了一个子线程并且让它开始运行。③ 两个线程同时、独立、互不干扰运行主线程飞快执行println然后main结束 →主线程死亡子线程进入while(true)死循环 →永远在运行④ 最终结果控制台会打印主线程结束了但是程序不会停止因为子线程还在死循环跑着。4.成员方法方法名称说明String getName()返回此线程的名称void setName(String name)设置线程的名字构造方法也可以设置名字static Thread currentThread()获取当前线程的对象static void sleep(long time)让线程休眠指定的时间单位为毫秒setPriority(int newPriority)设置线程的优先级final int getPriority()获取线程的优先级final void setDaemon(boolean on)设置为守护线程没有给线程设置名字线程也是有默认的名字的格式Thread-XX序号从0开始1. sleep () 和 wait () 的区别表格特性Thread.sleep()Object.wait()所属类Thread 静态方法Object 成员方法锁资源不释放锁释放锁使用场景单纯的延时、暂停线程间通信等待 / 通知唤醒方式时间到自动唤醒必须用 notify ()/notifyAll () 唤醒线程状态TIMED_WAITINGWAITING/TIMED_WAITING2. 中断休眠其他线程可以调用线程对象.interrupt()中断正在休眠的线程会立即抛出 InterruptedException结束休眠。2.优先级方法的调用Java 线程优先级用1~10的整数表示Thread类自带三个常量Thread.MIN_PRIORITY1最低优先级Thread.NORM_PRIORITY5默认优先级所有线程默认都是 5Thread.MAX_PRIORITY10最高优先级public class PriorityDemo { public static void main(String[] args) { Thread t1 new Thread(() - { for (int i 0; i 5; i) { System.out.println(低优先级线程); } }); Thread t2 new Thread(() - { for (int i 0; i 5; i) { System.out.println(高优先级线程); } }); // 设置优先级 t1.setPriority(1); // 最低 t2.setPriority(10); // 最高 t1.start(); t2.start(); } }优先级不能控制执行顺序优先级高 抢到 CPU 概率大优先级低 抢到 CPU 概率小绝不是高优先级线程执行完低优先级才执行。主线程默认优先级也是 5子线程继承父线程优先级主线程创建的子线程默认优先级和主线程一样5。优先级设置必须在 start () 之前线程启动之后再setPriority()基本无效5.Thread.yield () 方法详解1. 官方定义yield()礼让线程Thread.yield();作用当前线程主动让出 CPU 时间片从运行态回到就绪态重新参与 CPU 抢占。简单人话我现在不抢 CPU 了先歇一下大家重新排队抢 CPU我也在队伍里下一轮我依然有可能再次抢到 CPU。2. 核心特点不会释放锁最重要这是 90% 人搞错的点yield()只是让出 CPU持有锁的线程调用 yield锁依然握在手里不释放其他线程依然进不来同步代码块线程状态变化运行态 (Running) → 就绪态 (Runnable)不是阻塞态不是休眠只是建议调度器切换线程JVM 不一定听从yield 只是给操作系统线程调度器一个建议我空闲了可以调度别人了。调度器完全可以忽略马上又把 CPU 分给这个线程。代码解释public class YieldTest { public static void main(String[] args) { new Thread(() - { for (int i 0; i 5; i) { System.out.println(Thread.currentThread().getName() : i); Thread.yield(); // 礼让 } }, A).start(); new Thread(() - { for (int i 0; i 5; i) { System.out.println(Thread.currentThread().getName() : i); } }, B).start(); } }现象线程 A 每打印一次就礼让B 会穿插执行但顺序不稳定A 礼让后依旧可能立刻抢到 CPU。反例对比wait()释放 CPU 释放锁进入等待队列sleep()释放 CPU 时间片 不释放锁yield()让出 CPU 不释放锁6、synchronized 关键字的作用synchronized是 Java 中的关键字用于实现线程同步确保多线程环境下对共享资源的访问安全。它可以修饰方法或代码块防止多个线程同时访问同一资源从而避免数据不一致或竞态条件。synchronized 的用法修饰实例方法当synchronized修饰实例方法时锁的是当前实例对象this。同一时间只有一个线程能访问该对象的synchronized方法其他线程会被阻塞。public synchronized void method() { // 同步代码 }修饰静态方法当synchronized修饰静态方法时锁的是当前类的Class对象。同一时间只有一个线程能访问该类的静态同步方法。public static synchronized void staticMethod() { // 同步代码 }修饰代码块synchronized还可以修饰代码块并指定锁对象。锁对象可以是任意对象实例或类的Class对象。public void blockMethod() { synchronized (this) { // 锁当前实例 // 同步代码 } synchronized (ClassName.class) { // 锁类的 Class 对象 // 同步代码 } }synchronized 的原理synchronized的实现基于 JVM 的监视器锁Monitor。每个对象都有一个关联的 Monitor线程进入synchronized代码块时会尝试获取 Monitor 的所有权退出时释放所有权。进入同步块线程通过monitorenter指令获取锁。退出同步块线程通过monitorexit指令释放锁。synchronized 的特性可重入性同一线程可以多次获取同一把锁避免死锁。不可中断性一旦线程获取锁其他线程必须等待直到锁被释放。公平性默认是非公平锁但可以通过ReentrantLock实现公平锁。示例代码修饰代码块中的自定义锁对象方法public class LockAndCpuTest { // 唯一锁对象所有线程抢这一把锁 private static final Object lock new Object(); public static void main(String[] args) { // 线程A new Thread(() - { while (true) { synchronized (lock) { System.out.println(【线程A】抢到锁正在执行); try { Thread.sleep(1000); // 占用1秒方便看现象 } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(【线程A】释放锁了); } }, A).start(); // 线程B new Thread(() - { while (true) { synchronized (lock) { System.out.println(【线程B】抢到锁正在执行); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(【线程B】释放锁了); } }, B).start(); } }运行现象输出永远只会这样交替【线程A】抢到锁正在执行 【线程A】释放锁了 【线程B】抢到锁正在执行 【线程B】释放锁了完整底层流程拆解一开始 A、B 都在就绪队列一起抢 CPU操作系统调度随机先把 CPU 分给 AA 拿到 CPU开始跑代码A 走到synchronized(lock)尝试获取锁锁空闲 → A 拿到锁执行内部代码A 睡 1 秒全程持有锁此时线程 B 也抢到 CPU 了B 拿到 CPU 之后走到synchronized(lock)发现锁被 A 拿着 →抢锁失败→立刻放弃 CPU进入锁阻塞队列不再运行A 睡醒退出同步代码块 →释放锁锁空闲后阻塞队列里的 B 被唤醒回到就绪态下次 CPU 调度到 BB 就能拿到锁执行结合 yield () 的改造示例public class YieldNotReleaseLock { private static final Object lock new Object(); public static void main(String[] args) { new Thread(() - { synchronized (lock) { System.out.println(线程A拿到锁); Thread.yield(); // 礼让让出CPU System.out.println(线程A再次抢到CPU锁还在手里); } }, A).start(); new Thread(() - { System.out.println(线程B尝试抢CPU); synchronized (lock) { System.out.println(线程B拿到锁); } }, B).start(); } }yield 代码运行结果线程A拿到锁 线程B尝试抢CPU // 此处A调用yield让出CPU // 但锁没放B就算抢到CPU也进不来锁 线程A再次抢到CPU锁还在手里 线程A释放锁 线程B拿到锁锁之间的安全问题简单说用了多把锁结果本该互斥的代码没互斥导致多线程同时修改共享数据数据错乱、线程不安全。两大核心安全问题问题 1锁对象不一致 → 锁失效最常见现象多个线程用不同的锁导致同步代码不互斥同时执行数据乱掉。举例共享变量count要保证自增安全Object lock1 new Object(); Object lock2 new Object(); // 线程A new Thread(()-{ synchronized(lock1){ count; } }).start(); // 线程B new Thread(()-{ synchronized(lock2){ count; } }).start();安全问题分析lock1、lock2 是两把独立锁线程 A 拿锁 1线程 B 拿锁 2互不阻塞、同时运行同时修改count→线程不安全数据错误结论只要锁对象不一样synchronized 形同虚设共享资源必须共用同一把锁才安全。问题 2锁粒度混乱this 锁、class 锁混用对应三种 synchronized实例方法锁锁this静态方法锁锁类.class代码块自定义锁安全问题this 锁 和 class 锁 是两把完全不同的锁互不干涉// 实例方法锁锁 this public synchronized void add(){} // 静态方法锁锁 Test.class public static synchronized void sub(){}线程调用add()线程同时调用sub()两个方法会同时执行互不阻塞结论实例锁this只管住实例同步方法静态锁class只管住静态同步方法两者之间毫无互斥关系同时执行照样不安全开发中正确的安全锁规范针对同一个共享资源比如计数器、库存、用户数据所有操作它的代码必须共用同一把锁锁对象要写成private static final Object lock new Object();static所有对象共用这一把锁final锁对象引用不变不会换锁绝对不要不要用new Object()临时当锁不要每个线程新建锁不要混用 this 锁、class 锁不要随便用字符串常量当锁7、线程的join方法join () 是什么Thread.join()线程插队、等待线程执行完毕直白人话主线程 / 当前线程 停下来等待调用 join () 的这个线程跑完、结束死亡之后自己再继续往下执行。代码示例public class JoinTest { public static void main(String[] args) throws InterruptedException { Thread t new Thread(() - { for (int i 1; i 5; i) { System.out.println(子线程 i); try { Thread.sleep(500); } catch (Exception e) {} } }); t.start(); // 主线程调用 t.join() t.join(); // 下面这句**必须等子线程全部跑完才会打印** System.out.println(子线程结束主线程继续执行); } }运行结果永远顺序子线程 1、2、3、4、5 全部打完→ 才打印主线程最后一句话核心原理谁调用 join就等谁死 :A线程里写B.join()→A 暂停等待 B 线程全部执行完毕、死亡A 才恢复运行底层本质wait ()join()源码内部就是调用了Object.wait()所以join () 会释放锁再补一个带锁的例子验证 join 释放锁public class JoinReleaseLock { private static final Object lock new Object(); public static void main(String[] args) throws InterruptedException { Thread t1 new Thread(() - { synchronized (lock) { System.out.println(t1拿到锁); try { Thread.sleep(1000); } catch (Exception e) {} System.out.println(t1执行完毕); } }); Thread t2 new Thread(() - { synchronized (lock) { System.out.println(t2拿到锁); } }); t1.start(); t1.join(); // 主线程等t1并且**释放锁** t2.start(); }现象t1 跑完 → 锁释放 → t2 顺利拿到锁8、Object类的wait()、notify()、notifyAll()方法​​​​​​方法详细说明1. wait()让当前线程进入等待队列自动释放持有的锁最关键线程状态RUNNABLE → WAITING必须被notify()/notifyAll()唤醒重载wait()无限等待,必须被唤醒wait(long millis)超时自动醒2. notify()随机唤醒一个在该对象上等待的线程不立即释放锁要等同步代码执行完才释放唤醒后线程进入就绪态重新抢锁3. notifyAll()唤醒所有在该对象上等待的线程所有线程一起抢锁实际开发推荐用 notifyAll ()更安全避免死等必须遵守的 3 条铁律必须在synchronized同步代码 / 方法里调用 ,不在锁里调用 → 直接抛IllegalMonitorStateException必须是 锁对象 调用例如synchronized(lock)→ 必须用lock.wait()、lock.notify()wait () 会释放锁notify () 不会立刻释放锁代码示例public class WaitTest { private static final Object lock new Object(); public static void main(String[] args) { // 线程A等待 new Thread(() - { synchronized (lock) { System.out.println(A拿到锁); try { lock.wait(); // 等待释放锁 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(A被唤醒继续执行); } }, A).start(); // 线程B唤醒 new Thread(() - { try { Thread.sleep(1000); } catch (Exception e) {} synchronized (lock) { System.out.println(B拿到锁); lock.notify(); // 唤醒等待的线程A System.out.println(B唤醒了A); } }, B).start(); } }执行流程A 抢到 CPU拿到锁A 调用wait()→释放锁 让出 CPUB 抢到 CPU顺利拿到锁B 调用notify()唤醒 AB 执行完同步代码块释放锁A 被唤醒回到就绪态重新抢 CPU、抢锁继续执行四大线程方法对比方法所属类是否让出 CPU是否释放锁线程状态唤醒条件sleep()Thread让出不释放阻塞时间到yield()Thread让出不释放就绪重新抢 CPUjoin()Thread让出释放锁等待阻塞目标线程死亡wait()Object让出释放锁等待阻塞notify/notifyAll9、Java 线程安全类 非线程安全类1. 非线程安全类速度快无锁代表ArrayList、HashMap、StringBuilder内部没有任何锁多线程同时改数据错乱、丢数据、炸异常执行效率极高2. 线程安全类慢加锁保护代表Vector、Hashtable、StringBuffer内部自带 synchronized 锁多线程同时操作不会乱同一时间只有一个线程能改性能差10、什么是死锁直白定义多个线程互相持有对方需要的锁并且都不肯释放自己手里的锁无限等待程序卡死不动。死锁必须同时满足4 个必要条件面试必背这四个缺一不可只要破坏任意一个死锁就不会发生。互斥条件一把锁同一时间只能被一个线程持有别人抢不到。synchronized 天生满足请求保持条件线程已经拿着一把锁了不释放手里的锁又去申请别人的锁。不可剥夺条件锁只能持有者主动释放别人不能强行抢走锁。synchronized 天生满足循环等待条件线程 A 等线程 B 的锁线程 B 等线程 A 的锁形成环形等待。死锁经典代码示例标准面试代码两把锁两个线程完美死锁public class DeadLockTest { // 锁1、锁2 两个独立对象锁 private static final Object lock1 new Object(); private static final Object lock2 new Object(); public static void main(String[] args) { // 线程A先拿lock1再要lock2 new Thread(() - { synchronized (lock1) { System.out.println(线程A拿到锁1); try { Thread.sleep(1000); } catch (Exception e) {} // 不释放lock1继续请求lock2 synchronized (lock2) { System.out.println(线程A拿到锁2); } } }, A).start(); // 线程B先拿lock2再要lock1 new Thread(() - { synchronized (lock2) { System.out.println(线程B拿到锁2); try { Thread.sleep(1000); } catch (Exception e) {} // 不释放lock2继续请求lock1 synchronized (lock1) { System.out.println(线程B拿到锁1); } } }, B).start(); } }运行结果卡死线程A拿到锁1 线程B拿到锁2然后程序永远卡住不再输出任何内容卡死原因拆解A 持有lock1等待lock2B 持有lock2等待lock1互相等待都不释放自己手里的锁满足全部 4 个死锁条件 → 死锁11、守护线程1. 线程分类对比用户线程默认main主线程、业务线程JVM需等待所有用户线程全部结束后才会退出守护线程后台线程后台辅助线程需手动设置依附于用户线程生存不影响JVM退出2. 核心特性灵魂要点所有用户线程全部结束 → JVM立即退出 → 守护线程被强制终止无论任务是否执行完毕代码示例public class DaemonTest { public static void main(String[] args) { // 用户线程默认 Thread userThread new Thread(() - { for (int i 1; i 5; i) { System.out.println(用户线程 i); try { Thread.sleep(1000); } catch (Exception e) {} } }); // 守护线程 Thread daemonThread new Thread(() - { while (true) { // 无限循环 System.out.println(守护线程后台运行中...); try { Thread.sleep(1000); } catch (Exception e) {} } }); daemonThread.setDaemon(true); // 设置守护线程 userThread.start(); daemonThread.start(); } }运行现象守护线程一直在无限循环打印用户线程跑完 5 次结束瞬间JVM 退出守护线程直接被杀死循环强行终止程序直接结束不会等守护线程跑完。守护线程高频注意事项面试重点设置时机setDaemon(true) 必须在start()之前线程启动后无法修改守护状态finally执行守护线程被强制终止时finally代码块不一定执行可能来不及运行CPU与锁守护线程仍会参与CPU抢占、锁竞争也可能发生死锁与普通线程规则一致状态继承父线程是守护线程其创建的子线程默认也是守护线程禁用场景禁止用于执行文件写入、数据库操作、资源关闭等任务易导致数据损坏、资源泄露常用场景日志收集、心跳检测、缓存清理、JVM自带的GC垃圾回收线程当守护线程正在执行任务时若所有用户线程全部结束JVM 会直接强制终止守护线程此时守护线程中 finally 代码块可能来不及执行并非一定能执行完成。关键补充正常用户线程执行到 finally 代码块时会确保执行完毕除非程序异常终止守护线程因 JVM 退出是 “强制终止”不会等待守护线程的 finally 代码执行可能导致 finally 中用于关闭资源、释放锁的代码未运行进而引发资源泄露。12、线程池ThreadPoolExecutor 7 大核心参数public ThreadPoolExecutor( int corePoolSize, //1.核心线程数常驻线程空闲也不销毁除非开启allowCoreThreadTimeOut int maximumPoolSize, //2.最大线程数 核心线程 临时线程 long keepAliveTime, //3.临时线程空闲超时时间 TimeUnit unit, //4.keepAliveTime的时间单位 BlockingQueueRunnable workQueue, //5.阻塞队列存来不及执行的任务 ThreadFactory threadFactory, //6.线程工厂用来创建线程可以自定义线程名字 RejectedExecutionHandler handler //7.拒绝策略任务满了之后怎么处理新来任务 )参数通俗理解举例子corePoolSize2maximumPoolSize5keepAliveTime2s队列容量 10来了任务 → 先看核心线程少于 2 就新建核心线程执行任务核心线程满了 → 新任务放进阻塞队列排队队列最多存 10 个队列也满了 → 创建临时线程最多到最大线程数 5 个线程总数达到最大 5队列也满 → 触发拒绝策略临时线程空闲超过 2 秒 → 自动销毁核心线程默认保留4 种内置拒绝策略AbortPolicy默认直接抛RejectedExecutionException异常DiscardPolicy丢掉新来的任务不抛异常DiscardOldestPolicy丢掉队列里最老的任务再尝试提交当前任务CallerRunsPolicy交给提交任务的主线程执行不会抛异常基础使用 ThreadPoolExecutorimport java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class ThreadPoolDemo { public static void main(String[] args) { //1. 创建线程池 ThreadPoolExecutor pool new ThreadPoolExecutor( 2, //核心线程2 5, //最大线程5 2, //临时线程空闲2秒销毁 TimeUnit.SECONDS, new ArrayBlockingQueue(10) //阻塞队列容量10 ); //2. 提交任务execute() 接收Runnable任务无返回值 for (int i 1; i 6; i) { int taskNum i; pool.execute(() - { System.out.println(任务 taskNum 执行线程 Thread.currentThread().getName()); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } }); } //3. 关闭线程池 pool.shutdown(); //shutdown(): 不再接收新任务等待队列里已有的任务全部执行完再关闭 //pool.shutdownNow(): 强制关闭尝试中断正在执行的任务丢弃队列任务 } }execute(Runnable)提交无返回值任务2提交带返回值任务Callable用submit()submit()可以接收 Callable返回Future用来拿返回结果import java.util.concurrent.*; public class ThreadPoolCallableDemo { public static void main(String[] args) throws ExecutionException, InterruptedException { ThreadPoolExecutor pool new ThreadPoolExecutor( 2, 5, 2, TimeUnit.SECONDS, new ArrayBlockingQueue(10) ); //提交Callable任务有返回值 FutureString future pool.submit(() - { return 线程任务执行结果; }); //get()阻塞等待任务完成获取返回值 String res future.get(); System.out.println(res); pool.shutdown(); } }✔execute()Runnable无返回 ✔submit()Runnable / Callable有返回 Future欢迎大家评论交流一起加油

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询