Java 的多线程是一种允许在一个程序中同时运行多个线程的技术。每个线程是独立的执行路径,可以并发执行,从而提高程序的效率和响应能力。
1. 线程基础
Java 中的线程可以通过继承 Thread 类或实现 Runnable 接口来创建和管理。
1.1 继承 Thread 类
- class MyThread extends Thread {
- public void run() {
- System.out.println("Thread is running...");
- }
- }
- public class TestThread {
- public static void main(String[] args) {
- MyThread t1 = new MyThread();
- t1.start(); // 启动线程
- }
- }
复制代码 run() 方法包罗线程执行的代码,而 start() 方法用于启动新线程。
1.2 实现 Runnable 接口
- class MyRunnable implements Runnable {
- public void run() {
- System.out.println("Thread is running...");
- }
- }
- public class TestRunnable {
- public static void main(String[] args) {
- MyRunnable myRunnable = new MyRunnable();
- Thread t1 = new Thread(myRunnable);
- t1.start(); // 启动线程
- }
- }
复制代码 通过实现 Runnable 接口的方式可以更机动地共享资源。
2. 线程的生命周期
线程在其生命周期中经历以下状态:
- 新建(New): 线程对象被创建,但还没有调用 start() 方法。
- 停当(Runnable): 线程对象调用了 start() 方法,等待 CPU 调度。
- 运行(Running): 线程获得 CPU,开始执行 run() 方法的代码。
- 壅闭(Blocked): 线程由于某种缘故原由(如等待资源、睡眠)被挂起。
- 死亡(Dead): 线程执行完 run() 方法,或者因异常退出。
3. 线程控制
Java 提供了一些方法来控制线程的执行:
- sleep(long millis):让当火线程睡眠指定的毫秒数。
- join():等待该线程终止,也就是说等待当前的线程竣事, 才会继续执行下面的代码
- yield():停息当火线程,让出 CPU 给其他线程。
- interrupt():中断线程。
4. 线程同步
多线程程序中大概会出现多个线程同时访问共享资源的情况,导致数据不划一的问题。为相识决这个问题,可以利用同步技术。
4.1. ReentrantLock
ReentrantLock 提供了比 synchronized 更加机动的锁机制,可以显式地锁定息争锁。- import java.util.concurrent.locks.Lock;
- import java.util.concurrent.locks.ReentrantLock;
- public class ReentrantLockExample {
- private final Lock lock = new ReentrantLock();
- private int count = 0;
- public void increment() {
- lock.lock();
- try {
- count++;
- } finally {
- lock.unlock();
- }
- }
- public int getCount() {
- return count;
- }
- }
复制代码 4.2. ReadWriteLock
ReadWriteLock 提供了一对锁,一个用于读操作,一个用于写操作。这允许多个读线程同时访问共享资源,但在写线程访问时会独占锁。- import java.util.concurrent.locks.ReadWriteLock;
- import java.util.concurrent.locks.ReentrantReadWriteLock;
- public class ReadWriteLockExample {
- private final ReadWriteLock lock = new ReentrantReadWriteLock();
- private int count = 0;
- public void increment() {
- lock.writeLock().lock();
- try {
- count++;
- } finally {
- lock.writeLock().unlock();
- }
- }
- public int getCount() {
- lock.readLock().lock();
- try {
- return count;
- } finally {
- lock.readLock().unlock();
- }
- }
- }
复制代码 4.3 synchronized
在方法前利用 synchronized 关键字,确保同一时间只有一个线程可以执行该方法。- class Counter {
- private int count = 0;
- public synchronized void increment() {
- count++;
- }
- public int getCount() {
- return count;
- }
- }
复制代码 4.4 同步块
同步块可以更机动地控制需要同步的代码块,而不是整个方法。- class Counter {
- private int count = 0;
- public void increment() {
- synchronized (this) {
- count++;
- }
- }
- public int getCount() {
- return count;
- }
- }
复制代码 4.5 注意事项
下面代码中的写法, 不能保证同一时间只有一个线程可以执行该方法。
由于 4.3 和 4.4 中 synchronized 的写法是根据 this 来保证同一时间只有一个线程可以执行, 但是他们的 this 是不同的。(把 "需要替换的" 换成解释上的就可以 "保证同一时间只有一个线程可以执行")- class Worker implements Runnable {
- public static int cnt = 0;
- @Override
- public synchronized void run() {
- for (int i = 0; i < 100000; i ++) {
- cnt ++;
- }
- }
- }
- public class Main {
- public static void main(String[] args) throws InterruptedException {
-
- // Worker worker = new Worker();
- // Thread t1 = new Thread(worker);
- // Thread t2 = new Thread(worker);
- Thread t1 = new Thread(new Worker()); // 需要替换
- Thread t2 = new Thread(new Worker()); // 需要替换
- t1.start();
- t2.start();
- t1.join();
- t2.join();
- System.out.println(Worker.cnt);
- }
- }
复制代码 固然, 4.4 的代码也可以写成下面这样,这样他就是根据 lock 这个对象来保证同步的, java中的对象都可以当作lock- class Counter {
- public static final Object lock = new Object();
- private int count = 0;
- public void increment() {
- synchronized (lock ) {
- count++;
- }
- }
- public int getCount() {
- return count;
- }
- }
复制代码 5. 线程通信
Java 提供了 wait(), notify(), notifyAll() 方法来实现线程间的通信。
- wait():让当火线程等待,直到其他线程调用 notify() 或 notifyAll()。
- notify():唤醒一个正在等待的线程。
- notifyAll():唤醒所有正在等待的线程。
6. 线程池
利用线程池可以有效地管理和复用线程,淘汰创建和销毁线程的开销。Java 提供了 Executor 框架来管理线程池。- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- public class TestThreadPool {
- public static void main(String[] args) {
- ExecutorService executor = Executors.newFixedThreadPool(5);
- for (int i = 0; i < 10; i++) {
- executor.execute(new MyRunnable());
- }
- executor.shutdown();
- }
- }
复制代码 7. 高级线程工具
Java 提供了很多高级线程工具,如 Semaphore, CountDownLatch, CyclicBarrier 等,用于复杂的线程协调和同步。
7.1 Semaphore
信号量控制同时访问特定资源的线程数量。- import java.util.concurrent.Semaphore;
- public class TestSemaphore {
- private static final Semaphore semaphore = new Semaphore(3);
- public static void main(String[] args) {
- for (int i = 0; i < 10; i++) {
- new Thread(new Task()).start();
- }
- }
- static class Task implements Runnable {
- public void run() {
- try {
- semaphore.acquire();
- System.out.println("Thread " + Thread.currentThread().getName() + " is accessing the resource.");
- Thread.sleep(2000);
- semaphore.release();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- }
复制代码 7.2 CountDownLatch
允许一个或多个线程等待,直到在其他线程中执行的一组操作完成。- import java.util.concurrent.CountDownLatch;
- public class TestCountDownLatch {
- private static final int THREAD_COUNT = 3;
- private static final CountDownLatch latch = new CountDownLatch(THREAD_COUNT);
- public static void main(String[] args) {
- for (int i = 0; i < THREAD_COUNT; i++) {
- new Thread(new Task()).start();
- }
- try {
- latch.await(); // 主线程等待所有子线程完成
- System.out.println("All threads have finished.");
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- static class Task implements Runnable {
- public void run() {
- System.out.println("Thread " + Thread.currentThread().getName() + " is working.");
- latch.countDown(); // 计数器减一
- }
- }
- }
复制代码 结论
Java 多线程是一个强盛且复杂的技术,需要深入明白和警惕利用,以制止潜在的并发问题和死锁情况。通过合理地利用线程同步、线程通信和线程池等工具,可以编写高效且安全的多线程应用程序。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |