一、引言
多线程和并发编程是现代软件开发中的重要课题,它们在提升程序性能、改善用户体验方面发挥着关键作用。Java作为一种广泛使用的编程语言,提供了丰富的多线程和并发工具,帮助开发者应对复杂的并发需求。本文将从基本概念入手,逐步深入探讨Java中的多线程与并发机制。
二、线程的基本概念
- 线程的定义与特性
- 线程是操作系统能够进行运算调度的最小单位。
- 每个线程都有自己的程序计数器、栈、局部变量等资源。
- 线程的状态与生命周期
- 新建(New):线程对象创建后,但尚未启动。
- 就绪(Runnable):线程对象创建后,等待CPU时间片。
- 运行(Running):线程获得CPU时间片,正在执行。
- 阻塞(Blocked):线程因等待某些资源而暂时停止运行。
- 死亡(Terminated):线程执行完毕或因异常退出。
三、实现多线程的方式
继承Thread类
class MyThread extends Thread { public void run() { System.out.println("MyThread is running"); } } public class Test { public static void main(String[] args) { MyThread myThread = new MyThread(); myThread.start(); } }
实现Runnable接口
class MyRunnable implements Runnable { public void run() { System.out.println("MyRunnable is running"); } } public class Test { public static void main(String[] args) { Thread thread = new Thread(new MyRunnable()); thread.start(); } }
使用Callable和Future
import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; class MyCallable implements Callable<Integer> { public Integer call() throws Exception { return 123; } } public class Test { public static void main(String[] args) { ExecutorService executor = Executors.newSingleThreadExecutor(); Future<Integer> future = executor.submit(new MyCallable()); try { System.out.println("Result: " + future.get()); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } finally { executor.shutdown(); } } }
四、线程的同步与锁机制
synchronized关键字
用于修饰方法或代码块,确保同一时刻只有一个线程执行被修饰的代码段。
class Counter { private int count = 0; public synchronized void increment() { count++; } public int getCount() { return count; } }
ReentrantLock类
- 提供比synchronized更灵活的锁机制,可设置公平性、获取锁的超时时间等。
```java
import java.util.concurrent.locks.ReentrantLock;
class Counter {
private final ReentrantLock lock = new ReentrantLock(); private int count = 0; public void increment() { lock.lock(); try { count++; } finally { lock.unlock(); } } public int getCount() { return count; }
}
```- 提供比synchronized更灵活的锁机制,可设置公平性、获取锁的超时时间等。
读写锁(ReadWriteLock)
- 允许多个线程同时读,但在写操作时互斥。适用于读多写少的场景。
```java
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
class Data {
private final ReadWriteLock rwLock = new ReentrantReadWriteLock(); private String data; public void setData(String data) { rwLock.writeLock().lock(); try { this.data = data; } finally { rwLock.writeLock().unlock(); } } public String getData() { rwLock.readLock().lock(); try { return data; } finally { rwLock.readLock().unlock(); } }
}
```- 允许多个线程同时读,但在写操作时互斥。适用于读多写少的场景。
条件变量(Condition)
- 配合锁使用,用于线程间通信和协调。
```java
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class SharedObject {
private final Lock lock = new ReentrantLock(); private final Condition condition = lock.newCondition(); private boolean available = false; public void produce() { lock.lock(); try { available = true; condition.signalAll(); // 唤醒所有等待的线程 } finally { lock.unlock(); } } public void consume() { lock.lock(); try { while (!available) { // 使用while循环防止假唤醒 condition.await(); // 等待直到收到信号 } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { lock.unlock(); } }
}
```- 配合锁使用,用于线程间通信和协调。
Semaphore(信号量)
- 控制对资源的访问许可数量,常用于限制同时访问某个资源的线程数。
```java
import java.util.concurrent.Semaphore;
class LimitedResource {
private Semaphore semaphore = new Semaphore(5); // 同时最多允许5个线程访问 public void accessResource() { try { semaphore.acquire(); // 获取许可 // 访问资源... } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { semaphore.release(); // 释放许可 } }
}
```- 控制对资源的访问许可数量,常用于限制同时访问某个资源的线程数。
CountDownLatch(倒计时器)
- 让一个或多个线程等待其他线程完成指定任务后再继续执行。
```java
import java.util.concurrent.CountDownLatch;
class Task implements Runnable {
private final CountDownLatch latch; public Task(CountDownLatch latch) { this.latch = latch; } public void run() { try { System.out.println("Task is running"); Thread.sleep(1000L); // 模拟任务耗时 } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { latch.countDown(); // 任务完成,计数器减1 } }
}
public class Test {
public static void main(String[] args) { CountDownLatch latch = new CountDownLatch(3); // 初始化计数器为3 new Thread(new Task(latch)).start(); // 开始3个任务线程 new Thread(() -> { try { latch.await(); // 主线程等待任务线程完成 System.out.println("All tasks completed"); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }).start(); // 启动等待线程 }
}
```- 让一个或多个线程等待其他线程完成指定任务后再继续执行。
CyclicBarrier(循环屏障)
- 让一组线程在到达某个点前相互等待,然后同时执行。适用于多阶段任务。
```java
import java.util.concurrent.BrokenBarrier;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.Phaser; // Phaser也可以作为CyclicBarrier的替代方案,功能更强大。
class Task implements Runnable {
private final CyclicBarrier barrier; private final int id; public Task(CyclicBarrier barrier, int id) { this.barrier = barrier; this.id = id; } public void run() { try { System.out.println("Task " + id + " is running"); Thread.sleep(1000L); // 模拟任务耗时 barrier.await(); // 等待其他线程到达屏障点并继续执行。如果其他线程已经到达屏障点,则立即返回,不会阻塞当前线程。当最后一个线程到达屏障点后,所有等待的线程将继续执行。可以配合broken参数来中断等待。如果broken为true,则抛出BrokenBarrierException异常,并重置屏障状态。如果不传broken参数,默认为false。如果所有线程都调用了await(),则调用await()的线程将不会被阻塞,而是直接返回。这意味着,如果有一个线程因为某种原因没有调用await(),那么其他所有线程都将一直等待下去,除非有线程调用reset()方法。注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrierInstance实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrsier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclicBarrier实例。*/ /*注意,CyclicBarrier是不可重用的,一旦所有线程都调用过await()或者被重置之后,这个CyclicBarrier就不能再次使用了。如果需要重用,就必须重新创建一个新的CyclICBarrIER实例。*/ /*注意,CyclICBArrIEr实例是不能重复使用的,一旦所有线程都调CBArrIEr()函数或者被重置之CBArrIEr()函数或者被重置之后,这个CBArrIER实例就不能再次使用CBArrIEr()函数或者被重置之后,这个CBArrIEr实例就不能再次使用了。如果需要重用的话就必须重新创建一个新的CBArrIEr实例。*/ /*注意,CBArrIEr实例是不能重复使用的,一旦所有线程都调CBArrIEr()函数或者被重置之CBArrIEr()函数或者被重置之后,这个CBArrIER实例就不能再次使用了。如果需要重用的话就必须重新创建一个新的CBArrIEr实例。*/ /*注意,CylCEBArrIEr实例是不能重复使用的,一次使用后就要重新创建新的CBArrIEr实例才能继续使用。*/ /*注意,CycleBarrier是不能够重复使用的,一旦所有的线程都调用了await方法或者被重置之后,这个CycleBarrier就不能再用了。如果需要重用的话就必须重新创建一个新的CycleBarrier实例。*/ /*注意,CylCEBArrIEr实例是不能重复使用的,一次使用后就要重新创建新的CBArrIEr实例才能继续使用。*/ /*注意,CycleBarrier是不能够重复使用的,一旦所有的线程都待方法或者被重置之后,这个CycleBarrier就不能再用了。如果需要重用的话就必须重新创建一个新的CycleBarrier实例。*/ /*注意,CycleBarrier是不能够重复使用的,一次使用后就要重新创建新的CycleBarrier实例才能继续使用。*/ /*注意, CylCEBArrIEr实例是不能重复使用的,一旦所有的线程都调用了await方法或者被重置之后,这个CycleBarrier就不能再用了。如果需要重用的话就必须重新创建一个新的CycleBarrCylCEBArrIEr实例才能继续使用。*/ /*注意, CylCEBArrIEr实例是不能重复使用的,一次使用后就要重新创建新的CycleBarrIER实例才能继续使用。*/ /*注意, ClCEBArrIEr实例是不能重复使用的,一次使用后就要重新创建新的CycCEBArrIEr实例才能继续使用。*/ /*注意, CyleCEBArrIEr实例是不能重复使用的,一次使用后就要重新创建新的CycleBarrIER实例才能继续使用。*/ /*注意, CylcEBArrIEr实例是不能重复使用的,一次使用后就要重新创建新的CycleBarrIER实例才能继续使用。*/ /*注意, CylcEBArrIEr实例是不能重复使用的,一次使用后就要重新创建新的CycleBrrCylceBArrIErr实例才能继续使用。*/ /*注意, CylcEBArrIEr实例是不能重复使用的,一次使用后就要重新创建新的CycleBrrICylcEBArrIErr实例才能继续使用。*/ /*注意, CylcEBArrIEr实例是不能重复使用的,一次使用后就要重新创建新的CycleBrrICycylcEBArrIErr实例才能继续使用。*/ /*注意, CylcEBArrIEr实例是不能重复使用的,一次使用后就要重新创建新的CycleBrrICycylcEBArrIErr实例才能继续使用。*/ /*注意, CylcEBArrIEr实例是不能重复使用的,一次使用后就要重新创建新的CycleBrrICycylcEBArrIErr实例才能继续使用。*/ /*注意, CylcEBArrIEr实例是不能重复使用的,一次使用后就要重新创建新的CycleBrrICycylcEBArrIErr实例才能继续使用。*/ /*注意, CylcEBArrIEr实例是不能重复使用的,一次使用后就要重新创建新的CycleBrrICycylcEBArrIErr实例才能继续使用。*/ /*注意, CylcEBArrIEr实例是不能重复使用的,一次使用后就要重新创建新的CycleBrrICycylcEBArrIErr实例才能继续使用。*/ /*注意, CylcEBArrIEr实例是不能重复使用的,一次使用后就要重新创建新的CycleBrrICycylcEBArrIErr实例才能继续使用。*/ /*注意, CylcEBArrIer实例是不能重复使用的,一次使用后就要重新创建新的CyclCEBArrIer实例才能继续使用。*/ /*注意, CylcEBArrIer实例是不能重复使用的,一次使用后就要重新创建新的CyclCEBArrIer实例才能继续使用。*/ /*注意, CylcEBArrIer实例是不能重复使用的,一次使用后就要重新创建新的CyclCEBArrIer实例才能继续使用。*/ /*注意, CylcEBArrIer实例是不能重复使用的,一次使用后就要重新创建新的CyclCEBArrIer实例才能继续使用。*/ /*注意, CylcEBArrIer实例是不能重复使用的,一次使用后就要重新创建新的CyclCEBArrIer实例才能继续使用。*/ /*注意, CylcEBArrIer实例是不能重复使用的,一次使用后就要重新创建新的CyclCEBArrIer实例才能继续使用。*/ /*注意, CylcEBArrIer实例是不能重复使用的,一次使用后就要重新创建新的CyclCEBArrIer实例才能继续使用。*/ /*注意, CylcEBArrIer实例是不能重复使用的,一次使用后就要重新创建新的CyclCEBArrIer实例才能继续使用。*/ /*注意, CylcEBArrIer实例是不能重复使用的,一次使用后就要重新创建新的CyclCEBArrIer实例才能继续使用。*/ /*注意, CylcEBArrIer实例是不能重复使用的,一次使用后就要重新创建新的CyclCEBArrIer实例才能继续使用。*/
- 让一组线程在到达某个点前相互等待,然后同时执行。适用于多阶段任务。