线程相关概念
程序 (Program)
进程 (Process)
线程 (Thread)
协程 (Coroutine)
- Go 语言特性。
- Java 21 版本引入虚线程,更加轻量级(占用资源如 CPU、内存、IO 更少)。
- Platform Thread 平台线程(基于操作系统)。
- Virtual Thread 虚线程(基于 JVM)。
进程和线程关系
- 一个进程中包含一个或者多个线程。
- 一个线程一定从属于某一个进程。
Java 中的线程 (Thread)
如何创建线程
创建线程方式一
继承 Thread
类并重写 run
方法,创建对象后调用 start
方法。
1 2 3 4 5 6 7 8 9 10 11 12
| public class MyThread extends Thread {
@Override public void run() { System.out.println("MyThread is running"); }
public static void main(String[] args) { MyThread t1 = new MyThread(); t1.start(); } }
|
创建线程方式二
实现 Runnable
接口并重写 run
方法,创建线程时将 Runnable
对象作为参数传递给 Thread
类的构造方法。
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class MyRunnable implements Runnable {
@Override public void run() { System.out.println("MyRunnable is running"); }
public static void main(String[] args) { MyRunnable myRunnable = new MyRunnable(); Thread t1 = new Thread(myRunnable); t1.start(); } }
|
创建线程方式三
利用 Callable
接口和 FutureTask
类。Callable
接口可以有返回值,并且可以抛出异常。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask;
public class MyCallable implements Callable<String> {
@Override public String call() throws Exception { return "MyCallable is running"; }
public static void main(String[] args) { MyCallable myCallable = new MyCallable(); FutureTask<String> futureTask = new FutureTask<>(myCallable); Thread t1 = new Thread(futureTask); t1.start();
try { String result = futureTask.get(); System.out.println(result); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } }
|
常用方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| System.out.println(Thread.currentThread().getName());
thread.start();
Thread current = Thread.currentThread();
String name = thread.getName();
thread.setName("NewThreadName");
Thread.sleep(1000);
thread.join();
|
线程安全问题
什么是线程安全问题
- 当多个线程同时访问和修改同一个共享资源时,可能会导致数据不一致或程序行为异常,这种现象被称为线程安全问题。
演示线程安全问题现象
以下代码展示了多个线程同时操作共享资源(银行账户余额)时可能导致数据不一致的问题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| public class BankAccount { private int balance = 1000;
public void withdraw(int amount) { if (balance >= amount) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } balance -= amount; System.out.println(Thread.currentThread().getName() + " 取钱成功,余额:" + balance); } else { System.out.println(Thread.currentThread().getName() + " 取钱失败,余额不足!"); } }
public static void main(String[] args) { BankAccount account = new BankAccount();
Runnable task = () -> { for (int i = 0; i < 3; i++) { account.withdraw(400); } };
Thread t1 = new Thread(task, "线程1"); Thread t2 = new Thread(task, "线程2");
t1.start(); t2.start(); } }
|
解决线程安全问题的方案 (管程) Monitor
线程同步方案
synchronized 关键字
synchronized
是 Java 提供的内置锁机制,用于实现线程同步。
- 可以用于同步代码块或同步方法,确保同一时刻只有一个线程可以访问同步区域。
同步代码块
- 锁对象可以是
this
(当前实例)、class
(当前类的 Class 对象)。
1 2 3 4 5 6 7 8 9 10 11
| public void method() { synchronized (this) { } }
public static void staticMethod() { synchronized (MyClass.class) { } }
|
同步方法
- 实例方法的锁对象是
this
,静态方法的锁对象是当前类的 Class
对象。
1 2 3 4 5 6 7
| public synchronized void instanceMethod() { }
public static synchronized void staticMethod() { }
|
锁
ReentrantLock
- 可重入锁,支持公平锁和非公平锁。
- 提供了
tryLock()
方法,可以尝试获取锁而不会阻塞线程。
1 2 3 4 5 6 7 8 9 10 11
| Lock lock = new ReentrantLock();
if (lock.tryLock()) { try { } finally { lock.unlock(); } } else { }
|
线程通信
线程池
什么是线程池
如何创建线程池
使用 ThreadPoolExecutor 创建线程池
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit;
public class CustomThreadPoolExample { public static void main(String[] args) { ThreadPoolExecutor threadPool = new ThreadPoolExecutor( 2, 4, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(10), r -> new Thread(r, "CustomThread"), new ThreadPoolExecutor.AbortPolicy() );
for (int i = 0; i < 8; i++) { final int task = i; threadPool.execute(() -> { System.out.println("执行任务 " + task + " 的线程:" + Thread.currentThread().getName()); }); }
threadPool.shutdown(); } }
|
使用 Executors 工具类创建线程池
Executors
提供了多种便捷方法来创建线程池。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;
public class ThreadPoolExample { public static void main(String[] args) { ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
for (int i = 0; i < 5; i++) { final int task = i; fixedThreadPool.execute(() -> { System.out.println("执行任务 " + task + " 的线程:" + Thread.currentThread().getName()); }); }
fixedThreadPool.shutdown(); } }
|
在线程池中执行任务
执行 Runnable 任务
- 使用线程池执行
Runnable
任务时,可以通过 execute
方法提交任务。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;
public class RunnableTaskExample { public static void main(String[] args) { ExecutorService threadPool = Executors.newFixedThreadPool(3);
Runnable task = () -> { System.out.println("执行 Runnable 任务的线程:" + Thread.currentThread().getName()); };
threadPool.execute(task);
threadPool.shutdown(); } }
|
执行 Callable 任务
- 使用线程池执行
Callable
任务时,可以通过 submit
方法提交任务,并通过返回的 Future
对象获取结果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future;
public class CallableTaskExample { public static void main(String[] args) { ExecutorService threadPool = Executors.newFixedThreadPool(3);
Callable<String> task = () -> { return "执行 Callable 任务的线程:" + Thread.currentThread().getName(); };
try { Future<String> future = threadPool.submit(task); System.out.println(future.get()); } catch (Exception e) { e.printStackTrace(); } finally { threadPool.shutdown(); } } }
|
线程池工具类 Executors