线程是程序中的执行流,多个线程可以并发执行多个任务。例如,一家公司办理银行业务,多个员工分别处理转账、发福利、缴社保,这就是多线程的典型场景。

方式 | 示例代码 |
|---|---|
继承Thread类 | class MyThread extends Thread { public void run() { ... } } |
实现Runnable接口 | class MyRunnable implements Runnable { public void run() { ... } } |
匿名内部类 | new Thread(() -> { ... }).start(); |
Lambda表达式 | new Thread(() -> System.out.println("Hello")).start(); |
import java.util.Random;
public class ThreadDemo {
private static class MyThread extends Thread {
@Override
public void run() {
Random random = new Random();
while (true) {
System.out.println(Thread.currentThread().getName());
try {
Thread.sleep(random.nextInt(10));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
MyThread t1 = new MyThread();
t1.start();
Random random = new Random();
while (true) {
System.out.println(Thread.currentThread().getName());
try {
Thread.sleep(random.nextInt(10));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}package Thread;
public class Demo5 {
public static void main(String[] args) {
// 使用lambda表达式
Thread thread1 = new Thread(() -> {
while (true) {
System.out.println("hello thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}, "thread-1");
thread1.start();
}
}
多线程能充分利用多核CPU,提高程序运行效率。以下是一个对比串行与并发执行的示例:
public class ThreadAdvantage {
private static final long count = 10_0000_0000;
public static void main(String[] args) throws InterruptedException {
concurrency();
serial();
}
private static void concurrency() throws InterruptedException {
long begin = System.nanoTime();
Thread thread = new Thread(() -> {
int a = 0;
for (long i = 0; i < count; i++) a--;
});
thread.start();
int b = 0;
for (long i = 0; i < count; i++) b--;
thread.join();
long end = System.nanoTime();
double ms = (end - begin) * 1.0 / 1000 / 1000;
System.out.printf("并发: %f 毫秒%n", ms);
}
private static void serial() {
long begin = System.nanoTime();
int a = 0;
for (long i = 0; i < count; i++) a--;
int b = 0;
for (long i = 0; i < count; i++) b--;
long end = System.nanoTime();
double ms = (end - begin) * 1.0 / 1000 / 1000;
System.out.printf("串行: %f 毫秒%n", ms);
}
}方法 | 说明 |
|---|---|
Thread() | 创建线程对象 |
Thread(Runnable target) | 使用Runnable对象创建线程 |
Thread(String name) | 创建命名线程 |
Thread(Runnable target, String name) | 使用Runnable创建命名线程 |
属性 | 获取方法 |
|---|---|
ID | getId() |
名称 | getName() |
状态 | getState() |
优先级 | getPriority() |
是否后台线程 | isDaemon() |
是否存活 | isAlive() |
是否被中断 | isInterrupted() |
Thread t = new Thread(() -> System.out.println("线程运行"));
t.start(); // 真正启动线程public class ThreadDemo {
private static class MyRunnable implements Runnable {
public volatile boolean isQuit = false;
@Override
public void run() {
while (!isQuit) {
System.out.println("转账中...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("停止转账");
}
}
public static void main(String[] args) throws InterruptedException {
MyRunnable target = new MyRunnable();
Thread t = new Thread(target, "李四");
t.start();
Thread.sleep(5000);
target.isQuit = true;
}
}package Thread;
//中断线程
//通过调用线程的interrupt()方法,来中断线程
public class Demo8 {
public static void main(String[] args) throws InterruptedException {
// 注意,此处针对lambda的定义其实是在new Thread之前的!
// 所以如果在lambda中使用thread,是会报错的!
Thread thread = new Thread(() -> {
// currentThread()是Thread提供的一个静态方法
// 它的功能是哪个线程调用这个方法,就返回哪个线程对象的引用
while (!Thread.currentThread().isInterrupted()) {
// 由于这个 currentThread()方法,是在后续thread.start 之后,才执行的.
// 并且是在thread线程中执行的。返回的结果就是指向thread线程对象的引用了
System.out.println("hello thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// 如果线程在sleep状态时,被中断了,会触发InterruptedException异常
// 当线程thread正在sleep时,主线程(main)调用thread的interrupt方法,可以提前唤醒sleep状态的线程,此时会触发InterruptedException异常。通过这个异常,能区分线程是正常休眠结束还是被提前中断唤醒。并且,当sleep因提前唤醒触发异常后,会将线程的中断标志位(isInterrupted)重置为false。因此会无限循环!
// 这个printStackTrace()方法,只是用来打印异常的栈轨迹的。
e.printStackTrace();
// 当线程在sleep状态时被中断,会抛出InterruptedException异常。我们可以在catch块中处理这个异常,例如记录日志、清理资源等。同时,我们可以根据业务需求,选择是否继续循环或退出线程或稍等一会儿在退出循环。这里我们选择退出线程
// 添加break之后,触发异常时就会结束循环,让线程结束
// 在break之前也可以添加一些其他善后逻辑,相当于稍后再结束
// doSomething();
break;
// 使用IDEA自动生成catch语句,此时默认给的代码就是再次抛出一个其他异常,如RuntimeException,但是这个做法太粗暴了,它不只是让thread线程结束,也会使整个进程结束,因为没有人catch这个RuntimeException异常。不推荐
// throw new RuntimeException(e);
}
}
});
thread.start();
// 在main线程中尝试终止thread线程
Thread.sleep(3000);
thread.interrupt();
}
}package Thread;
//join方法(主线程等thread线程结束)
public class Demo9 {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("hello thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
// e.printStackTrace();
break;
}
}
});
thread.start();
// 在主线程中就可以对thread线程进行等待
System.out.println("主线程等待之前");
// join也有可能触发阻塞,可能会抛出InterruptedException异常
// 哪个线程调用了join方法,哪个线程就是等的一方,此处是main
// join前面那个引用,对应的就是线程就是“被等的一方”
// 此处是main线程等待thread线程结束
thread.join();
System.out.println("主线程等待之后");
}
}
Thread currentThread = Thread.currentThread();
System.out.println(currentThread.getName());Thread.sleep(1000); // 休眠1秒
public class ThreadState {
public static void main(String[] args) {
for (Thread.State state : Thread.State.values()) {
System.out.println(state);
}
}
}状态包括:
NEW,RUNNABLE,BLOCKED,WAITING,TIMED_WAITING,TERMINATED。

[NEW]
|
| start()
v
[RUNNABLE] <----------------+
| |
| 获取CPU | yield()/时间片用完
v |
[RUNNING] ------------------+
|
| sleep()/wait()/join()
v
[TIMED_WAITING/WAITING]
|
| 时间到/notify()/interrupt()
v
[RUNNABLE] <----------------+
^ |
| | 获取锁
| 等待锁 |
+------------------------+
| |
v |
[BLOCKED] ------------------+
[RUNNING]
|
| 执行完毕
v
[TERMINATED]package Thread;
//线程安全
public class Demo14 {
private static int count = 0;
public static void main(String[] args) throws InterruptedException {
// 如果把上面的count移到这里,改成局部变量,那么就会出现lambda变量捕获报错。因为他不是final属性
// int count = 0;
Thread t1 = new Thread(() -> {
for (int i = 0; i < 50000; i++) {
count++;
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 50000; i++) {
count++;
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(count);
}
}实际打印结果基本都是小于100000 如果出现多次这种请款情况,那么实际打印结果甚至很可能会低于50000

原因 | 说明 |
|---|---|
线程调度是随机的 | 随机调度使⼀个程序在多线程环境下,执⾏顺序存在很多的变数 |
修改共享数据 | 如上面代码涉及到多个线程针对count 变量进⾏修改 |
原子性 | 操作被中断导致数据不一致 |
可见性 | 线程间数据更新不可见 |
指令重排序 | 编译器/CPU优化导致执行顺序变化 |
synchronized的特性 synchronized会起到互斥效果,某个线程执行到某个对象的synchronized中时,其他线程如果也执行到同⼀个对象synchronized就会阻塞等待.
package Thread;
//加锁和同步
public class Demo15 {
private static int count = 0;
private static Object lock = new Object();
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 50000; i++) {
// 进去synchronized代码块加锁,出去synchronized就是解锁
synchronized (lock) {
count++;
}
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 50000; i++) {
// 加锁就是把若干个操作“打包为一个原子”,不是说把count++三个指令变成成一个指令,也不是说,这三个指令要在cpu上一口气执行完不会触发调度
// 加锁会影响到其他加锁线程,而且是加同一个锁的线程
// 进去synchronized代码块加锁,出去synchronized就是解锁,()括号里面需要填一个对象,这个对象就是锁对象
// 只有当两个线程竞争同一把锁,才会产生“阻塞”,竞争不同的锁或者只有一个加锁另一个没加锁,则都不会产生“锁冲突、锁竞争”
synchronized (lock) {
count++;
}
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(count);
}
}
synchronized 加锁范围对多线程执行效率的影响
这张图核心讲解的是 synchronized 加锁范围对多线程执行效率的影响,需要结合“锁的粒度”和“并发场景”来分析:
一、左图:synchronized 加在 for 循环外
synchronized (locker) {
for (int i = 0; i < 50000; i++) {
count++;
}
}执行逻辑
t1 获取锁后,会持续持有锁,执行完整个 for 循环(5 万次 count++)后才释放锁。t2 必须等待 t1 完全释放锁,才能获取锁并执行自己的循环。效率特点
count++),“串行执行整个循环” 的总耗时比 “频繁加锁解锁” 更短。t2 完全被阻塞,直到 t1 执行完 5 万次循环,多线程几乎退化为 “单线程串行”。二、右图:synchronized 加在 for 循环内
for (int i = 0; i < 50000; i++) {
synchronized (locker) {
count++;
}
}执行逻辑
count++ 后立即释放锁。t1 和 t2 可以交替获取锁(t1 释放后,t2 能立即获取),实现一定程度的 “并发执行”。效率特点
synchronized 内部是复杂逻辑(如图中 “一系列很复杂的逻辑”),“缩小锁的范围” 能让非临界区代码并发执行,整体并发度更高,总效率会超过 “大锁范围” 的方式。三、核心结论:锁的粒度要 “恰到好处”
简单总结:锁的范围不是越大或越小越好,要根据任务的 “复杂度” 和 “并发需求” 来权衡,日常开发优先选择 “小粒度锁” 以保留更高的并发潜力。
public synchronized void increment() {
count++;
}public static synchronized void increment() {
count++;
}由于 Java 中 synchronized 锁是可重入锁,这种 “同一线程对同一把锁的嵌套加锁” 是安全的:
展示死锁
package Thread;
// 死锁示例
public class Demo17 {
// 创建两个锁对象
private static final Object lockA = new Object();
private static final Object lockB = new Object();
public static void main(String[] args) {
// 线程1:先获取lockA,再尝试获取lockB
Thread thread1 = new Thread(() -> {
synchronized (lockA) {
System.out.println("线程1已获取lockA,尝试获取lockB...");
// 休眠100ms,让线程2有机会获取lockB,增加死锁概率
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lockB) {
System.out.println("线程1已获取lockB");
}
}
});
// 线程2:先获取lockB,再尝试获取lockA(与线程1顺序相反)
Thread thread2 = new Thread(() -> {
synchronized (lockB) {
System.out.println("线程2已获取lockB,尝试获取lockA...");
// 休眠100ms,让线程1有机会获取lockA,增加死锁概率
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lockA) {
System.out.println("线程2已获取lockA");
}
}
});
// 启动两个线程
thread1.start();
thread2.start();
System.out.println("线程1和线程2已启动");
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程1和线程2已执行完毕");
}
}展示可重入性
// 针对一把锁连续加锁两次(锁的可重入性,避免死锁)
Thread thread3 = new Thread(() -> {
synchronized (counter) {
synchronized (counter) {
for (int i = 0; i < 50000; i++) {
counter.add();
}
}
}
});内存可见性问题解析 内存可见性问题指在多线程程序里,一个线程对共享变量的修改,其他线程无法及时察觉的现象。 原因(结合 CPU 寄存器、内存和 JMM)
volatile、锁等)时,JMM 不保证线程对共享变量的修改能被其他线程立即看到。volatile修饰的变量,能够保证"内存可见性".

public class VolatileDemo {
static class Counter {
public volatile int flag = 0;
}
public static void main(String[] args) {
Counter counter = new Counter();
Thread t1 = new Thread(() -> {
while (counter.flag == 0) {
// 空循环
}
System.out.println("循环结束");
});
Thread t2 = new Thread(() -> {
Scanner scanner = new Scanner(System.in);
System.out.println("输入整数:");
counter.flag = scanner.nextInt();
});
t1.start();
t2.start();
}
}潜在问题(结合编译器优化) 由于多线程环境下,线程间共享变量的可见性可能存在问题(若不加volatile关键字):
在 Java 中,wait() 和 notify() 是 Object 类的两个核心方法,用于多线程间的协作,通过控制线程的等待与唤醒,实现线程间的同步和通信。它们必须配合同步锁(synchronized) 使用,核心作用是让线程暂时释放锁并等待特定条件,直到其他线程满足条件后唤醒它。 1. wait() 方法
2. notify() 方法
package Thread;
import java.util.Scanner;
//wait和notify的使用
public class Demo21 {
private static Object locker = new Object();
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
System.out.println("t1 wait之前");
synchronized (locker) {
try {
locker.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("t1 wait之后");
});
Thread t2 = new Thread(() -> {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入任意内容,唤醒t1线程:");
scanner.next();
synchronized (locker) {
locker.notify();
}
});
t1.start();
t2.start();
}
}package Thread;
//单例模式————>饿汉模式
//Singleton就是单例的意思
class Singleton {
// 把这个唯一的实例先创建出来
// 由于此处的instance是一个static的,所以它会在类加载的时候就被创建出来(程序一启动时)
private static Singleton instance = new Singleton();
// 提供一个静态的方法,返回这个唯一的实例
public static Singleton getInstance() {
return instance;
}
// 核心操作:把构造方法私有化,防止外部直接new
private Singleton() {
}
}
public class Eager_Initialization {
public static void main(String[] args) {
// 做了一个君子协定,你必须通过getInstance()方法来获取实例,而不能直接new
// 如果有人不会遵守上述决定,那就打破单例了
// 所以要做一些措施
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
// Singleton s3 = new Singleton();
System.out.println(s1 == s2);
}
}package Thread;
//单例模式————>懒汉模式
class SingletonLazy {
private static SingletonLazy instance = null;
// 添加volatile为了不使编译器进行优化,防止触发指令重排序
private static volatile Object locker = new Object();
private SingletonLazy() {
// 防止通过反射破坏单例
if (instance != null) {
throw new RuntimeException("不能通过反射创建实例!");
}
System.out.println("SingletonLazy构造方法被调用");
}
// 提供一个静态的方法,返回这个唯一的实例
public static SingletonLazy getISingletonLazy() {
// 先判断是否已经创建了实例
if (instance == null) {
synchronized (locker) {
if (instance == null) {
// 如果没有创建实例,就创建一个
instance = new SingletonLazy();
}
}
}
return instance;
}
}
public class Lazy_Initialization {
public static void main(String[] args) {
SingletonLazy s1 = SingletonLazy.getISingletonLazy();
SingletonLazy s2 = SingletonLazy.getISingletonLazy();
// Singleton s3 = new Singleton();
System.out.println(s1 == s2);
}
}public class BlockingQueue {
private final int[] items;
private int head = 0;
private int tail = 0;
private int size = 0;
public BlockingQueue(int capacity) {
items = new int[capacity];
}
public synchronized void put(int value) throws InterruptedException {
while (size == items.length) {
wait();
}
items[tail] = value;
tail = (tail + 1) % items.length;
size++;
notifyAll();
}
public synchronized int take() throws InterruptedException {
while (size == 0) {
wait();
}
int value = items[head];
head = (head + 1) % items.length;
size--;
notifyAll();
return value;
}
}定时器是什么 定时器也是软件开发中的⼀个重要组件.类似于⼀个"闹钟".达到⼀个设定的时间之后,就执行某个指定好的代码

package Thread;
import java.util.PriorityQueue;
// 自己实现的定时器
// 定时器要同时管理多个任务
// 有一定的数据结构来管理多个任务
// 使用优先级队列(堆)
// 由于我们把这个类要放在优先级队列中,就需要指定优先级队列的“比较规则“
class MyTimerTask implements Comparable<MyTimerTask> {
private Runnable task;
// 这个地方为了和当前时间进行对比,确认这个任务是否要执行,保存时间戳更方便
private long time;
public MyTimerTask(Runnable task, long delay) {
this.task = task;
// 把delay转换成要执行任务的绝对时间戳记录下来
this.time = System.currentTimeMillis() + delay;
}
public Runnable getTask() {
return task;
}
public long getTime() {
return time;
}
@Override
public int compareTo(MyTimerTask o) {
// this - o就会实现一个小堆的效果
// o - this就会实现一个大堆的效果
// 这里我们要实现的是谁时间小,就先执行谁
return (int) (this.time - o.time);
}
}
class MyTimer {
private PriorityQueue<MyTimerTask> queue = new PriorityQueue<>();
private Object locker = new Object();
// 创建一个构造方法
public MyTimer() {
// 我们在这里要创建一个线程,让这个线程去检测是否到时间了,以及去执行这个任务
Thread thread = new Thread(() -> {
// 循环从队列中取出元素,然后来判定这个任务的时间是否到达
// 如果到达就执行任务,并且出队列
// 如果没到达时间,就暂时不执行
try {
while (true) {
synchronized (locker) {
// 判断队列是否为空
if (queue.isEmpty()) {
// 如果不处理会触发”忙等“问题,因为线程会一直占用CPU资源
// 所以我们要让线程进入等待状态,等下一次被唤醒
locker.wait();
}
// 取出队首元素
MyTimerTask task = queue.peek();
// 记录当前时刻的时间戳
long currentTime = System.currentTimeMillis();
// 判断是否到达时间
if (task.getTime() > currentTime) {
// 时间还没到,也会触发忙等,等待到时间再执行
// 这里的wake要处理两种情况
// 1. 随时有新任务加入,导致队首元素发生变化
// 2. 如果没有新任务,时间到了,线程被唤醒
// 如:任务是 14:30,就 wait 30 分钟
// 在这 30 分钟过程中,如果没有任何新的任务到来,30 分钟时间到,就应该被唤醒,进而去执行任务~~
// 如果在 30 分钟过程中,有新任务来了.新任务是 14:15 分的任务~~此时必然要把 wait 30 分钟唤醒, 根据最新的任务的时间,重新设定
// wait 时间.
// 如果在 30 分钟过程中,有新任务来了,新任务是 15:00 的任务虽然 wait 暂时唤醒了一下,还是依据 14:30 的任务,重新设置等待时间~~
locker.wait(task.getTime() - currentTime);
} else {
// 执行任务
task.getTask().run();
// 出队列
queue.poll();
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread.start();
}
// 创建schedule方法,此处的任务用Runnable表示
public void schedule(Runnable runnable, long delay) {
synchronized (locker) {
queue.offer(new MyTimerTask(runnable, delay));
locker.notify();
}
}
}
public class MyTimerDemo {
public static void main(String[] args) {
MyTimer timer = new MyTimer();
timer.schedule(new Runnable() {
@Override
public void run() {
System.out.println("定时器执行任务 3000");
}
}, 3000);
timer.schedule(new Runnable() {
@Override
public void run() {
System.out.println("定时器执行任务 2000");
}
}, 2000);
timer.schedule(new Runnable() {
@Override
public void run() {
System.out.println("定时器执行任务 1000");
}
}, 1000);
}
}线程池是一种线程管理机制,核心目的是减少线程创建与销毁的开销,提高系统资源利用率。
可通过一个生活场景类比理解:
1. 快速创建线程池(Executors工具类)
Executors是Java提供的线程池工具类,封装了ThreadPoolExecutor的复杂配置,可快速创建不同类型的线程池,返回值类型均为ExecutorService(线程池核心接口)。
通过ExecutorService.submit(Runnable task)可向线程池提交任务。
示例代码(固定线程数线程池
// 创建包含10个固定线程的线程池
ExecutorService pool = Executors.newFixedThreadPool(10);
// 向线程池提交任务
pool.submit(new Runnable() {
@Override
public void run() {
System.out.println("任务执行:hello");
}
});2. Executors创建线程池的4种方式
方法 | 功能描述 |
|---|---|
newFixedThreadPool(n) | 创建固定线程数的线程池,线程数始终为n,空闲线程不会被销毁。 |
newCachedThreadPool() | 创建动态增长的线程池,线程空闲60秒后会被销毁,适合短期高频任务。 |
newSingleThreadExecutor() | 创建单线程线程池,所有任务按顺序执行,避免多线程并发问题。 |
newScheduledThreadPool(n) | 创建定时/延迟执行的线程池,可替代Timer,支持周期性任务。 |
ThreadPoolExecutorExecutors本质是对ThreadPoolExecutor的封装。ThreadPoolExecutor提供7个核心参数,可精细化控制线程池行为,对应“快递店运营规则”的具象化。
7个核心参数(类比快递店场景)
参数名 | 作用(类比快递店) | 核心逻辑 |
|---|---|---|
corePoolSize | 正式员工数量 | 线程池维护的“核心线程数”,即使空闲也不会被销毁(除非开启allowCoreThreadTimeOut)。 |
maximumPoolSize | 正式员工 + 临时工总数 | 线程池允许的最大线程数,任务高峰期可临时创建线程(临时工),任务减少后临时工被辞退。 |
keepAliveTime | 临时工的空闲时间上限 | 当线程数超过corePoolSize时,多余线程(临时工)空闲超过该时间会被销毁。 |
unit | keepAliveTime的时间单位 | 可选TimeUnit.SECONDS(秒)、MILLISECONDS(毫秒)等。 |
workQueue | 任务队列(记录待处理业务的“本子”) | 核心线程都忙碌时,新任务会放入阻塞队列(如LinkedBlockingQueue)等待。 |
threadFactory | 创建线程的工厂 | 定制线程属性(如线程名称、优先级、是否为守护线程),默认使用Executors.defaultThreadFactory()。 |
RejectedExecutionHandler | 拒绝策略(业务超负载时的处理规则) | 任务队列满且线程数达maximumPoolSize时,触发拒绝策略。 |
4种默认拒绝策略
拒绝策略类 | 处理逻辑 |
|---|---|
AbortPolicy() | 默认策略,直接抛出RejectedExecutionException异常,中断任务提交。 |
CallerRunsPolicy() | 让“提交任务的线程”自己执行任务(如快递店老板亲自送快递),减轻线程池压力。 |
DiscardOldestPolicy() | 丢弃队列中“最老的任务”(最早进入队列的任务),再尝试提交新任务。 |
DiscardPolicy() | 直接丢弃“新提交的任务”,不抛出异常,适合非核心任务。 |
自行实现一个简单的固定线程池
package Thread;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.BlockingQueue;
// 自行实现一个简单的固定线程池
class FixedThreadPool {
// 创建一个阻塞队列
private BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();
// 创建一个构造方法
public FixedThreadPool(int n) {
for (int i = 0; i < n; i++) {
Thread thread = new Thread(() -> {
// 每个线程要完成的工作, 就是从队列中取出任务并执行任务
try {
while (true) {
Runnable task = queue.take();
task.run();
// 如果里面没有任务, 就会阻塞在take()方法上
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread.start();
}
}
public void sumbit(Runnable task) throws InterruptedException {
queue.put(task);
}
}
public class MyFixedThreadPool {
// 测试创建一个固定线程池
public static void main(String[] args) throws InterruptedException {
FixedThreadPool threadPool = new FixedThreadPool(5);
for (int i = 0; i < 10; i++) {
int id = i;
threadPool.sumbit(() -> {
System.out.println("Thread:" + id + " 执行完毕");
});
}
}
}对比项 | 进程 | 线程 |
|---|---|---|
资源分配 | 独立内存空间 | 共享进程资源 |
创建开销 | 大 | 小 |
切换开销 | 大 | 小 |
通信方式 | 复杂(IPC) | 简单(共享内存) |
本文详细介绍了Java多线程编程的基础知识、常见问题及解决方案,并提供了丰富的代码示例。掌握多线程编程是Java工程师的必备技能,希望本文能帮助你更好地理解和应用多线程技术。