Java 多线程
Java 多线程
一、线程的基本概念
-
线程是什么:
- 线程是程序执行的最小单位,它可以独立执行一段代码。
- 一个进程可以包含多个线程,它们共享进程的内存空间和资源。
-
线程的状态:
- 新建(New):线程刚刚被创建,还没有开始执行。
- 就绪(Runnable):线程已经准备好执行,等待 CPU 分配时间片。
- 运行(Running):线程正在执行。
- 阻塞(Blocked):线程因为等待某个条件而暂停执行,如等待输入、等待锁等。
- 死亡(Dead):线程执行完毕或因为异常而终止。
二、创建线程的方式
-
继承
Thread类:- 创建一个类继承自
Thread类,并重写run方法,在run方法中编写线程要执行的代码。 - 示例:
class MyThread extends Thread { @Override public void run() { System.out.println("This is a custom thread."); } } public class ThreadCreationExample { public static void main(String[] args) { MyThread thread = new MyThread(); thread.start(); } }
- 创建一个类继承自
-
实现
Runnable接口:- 创建一个类实现
Runnable接口,并实现run方法。 - 然后创建一个
Thread对象,将实现了Runnable接口的对象作为参数传递给Thread构造函数,并调用start方法启动线程。 - 示例:
class MyRunnable implements Runnable { @Override public void run() { System.out.println("This is a thread implemented using Runnable."); } } public class ThreadCreationRunnableExample { public static void main(String[] args) { MyRunnable runnable = new MyRunnable(); Thread thread = new Thread(runnable); thread.start(); } }
- 创建一个类实现
三、线程的优先级
-
设置优先级:
- Java 线程的优先级可以通过
setPriority方法来设置,范围从 1(最低优先级)到 10(最高优先级)。默认优先级为 5。 - 示例:
class MyHighPriorityThread extends Thread { @Override public void run() { System.out.println("High priority thread is running."); } } class MyLowPriorityThread extends Thread { @Override public void run() { System.out.println("Low priority thread is running."); } } public class ThreadPriorityExample { public static void main(String[] args) { MyHighPriorityThread highPriorityThread = new MyHighPriorityThread(); highPriorityThread.setPriority(Thread.MAX_PRIORITY); MyLowPriorityThread lowPriorityThread = new MyLowPriorityThread(); lowPriorityThread.setPriority(Thread.MIN_PRIORITY); highPriorityThread.start(); lowPriorityThread.start(); } }
- Java 线程的优先级可以通过
-
优先级的影响:
- 优先级高的线程并不一定总是先执行,只是在竞争资源时更有可能被调度执行。实际的执行顺序还取决于操作系统的调度算法。
四、线程同步
-
同步方法:
- 使用
synchronized关键字修饰方法,可以确保在同一时间只有一个线程能够访问该方法。 - 示例:
class Counter { private int count = 0; public synchronized void increment() { count++; } public int getCount() { return count; } } class MyThreadForCounter extends Thread { private Counter counter; public MyThreadForCounter(Counter counter) { this.counter = counter; } @Override public void run() { for (int i = 0; i < 1000; i++) { counter.increment(); } } } public class SynchronizedMethodExample { public static void main(String[] args) { Counter counter = new Counter(); MyThreadForCounter thread1 = new MyThreadForCounter(counter); MyThreadForCounter thread2 = new MyThreadForCounter(counter); thread1.start(); thread2.start(); try { thread1.join(); thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Final count: " + counter.getCount()); } }
- 使用
-
同步块:
- 使用
synchronized关键字修饰代码块,可以指定一个对象作为锁,确保在同一时间只有一个线程能够访问该代码块。 - 示例:
class CounterWithSyncBlock { private int count = 0; private Object lock = new Object(); public void increment() { synchronized (lock) { count++; } } public int getCount() { return count; } } class MyThreadForSyncBlock extends Thread { private CounterWithSyncBlock counter; public MyThreadForSyncBlock(CounterWithSyncBlock counter) { this.counter = counter; } @Override public void run() { for (int i = 0; i < 1000; i++) { counter.increment(); } } } public class SynchronizedBlockExample { public static void main(String[] args) { CounterWithSyncBlock counter = new CounterWithSyncBlock(); MyThreadForSyncBlock thread1 = new MyThreadForSyncBlock(counter); MyThreadForSyncBlock thread2 = new MyThreadForSyncBlock(counter); thread1.start(); thread2.start(); try { thread1.join(); thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Final count with sync block: " + counter.getCount()); } }
- 使用
五、线程间通信
wait和notify方法:wait方法使当前线程等待,直到另一个线程调用notify或notifyAll方法唤醒它。notify方法唤醒一个等待的线程,notifyAll方法唤醒所有等待的线程。- 示例:
class SharedResource { private int value = 0; private boolean available = false; public synchronized int getValue() { while (!available) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } available = false; notifyAll(); return value; } public synchronized void setValue(int value) { while (available) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } this.value = value; available = true; notifyAll(); } } class Producer extends Thread { private SharedResource resource; public Producer(SharedResource resource) { this.resource = resource; } @Override public void run() { for (int i = 1; i <= 10; i++) { resource.setValue(i); System.out.println("Produced: " + i); } } } class Consumer extends Thread { private SharedResource resource; public Consumer(SharedResource resource) { this.resource = resource; } @Override public void run() { for (int i = 1; i <= 10; i++) { int value = resource.getValue(); System.out.println("Consumed: " + value); } } } public class ThreadCommunicationExample { public static void main(String[] args) { SharedResource resource = new SharedResource(); Producer producer = new Producer(resource); Consumer consumer = new Consumer(resource); producer.start(); consumer.start(); } }
六、线程安全的集合类
-
ConcurrentHashMap:- 是一个线程安全的哈希表,支持高并发的读写操作。
- 示例:
import java.util.concurrent.ConcurrentHashMap; public class ConcurrentHashMapExample { public static void main(String[] args) { ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>(); map.put("apple", 5); map.put("banana", 3); Integer value = map.get("apple"); System.out.println("Value for 'apple': " + value); } }
-
CopyOnWriteArrayList:- 是一个线程安全的列表,在进行写操作时会复制一份原列表,避免了在迭代过程中的并发修改异常。
- 示例:
import java.util.concurrent.CopyOnWriteArrayList; public class CopyOnWriteArrayListExample { public static void main(String[] args) { CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>(); list.add("apple"); list.add("banana"); for (String item : list) { System.out.println(item); } } }
七、线程池
一、Java 线程池简介
线程池是一种多线程处理形式,它可以管理一组工作线程,在需要执行任务时从线程池中获取线程,任务执行完毕后将线程归还到线程池中,以实现线程的复用,减少线程创建和销毁的开销。
二、Java 线程池的主要组成部分
-
ThreadPoolExecutor:这是 Java 线程池的核心实现类,它接受一系列参数来配置线程池的行为。corePoolSize:核心线程数,即使线程处于空闲状态也会保留在池中。maximumPoolSize:最大线程数,当任务队列已满且有新任务提交时,线程池会创建新线程直到达到这个数量。keepAliveTime:当线程数大于核心线程数时,多余的空闲线程在这个时间后会被终止。unit:keepAliveTime的时间单位。workQueue:用于存储等待执行的任务的队列。threadFactory:用于创建线程的工厂。rejectedExecutionHandler:当任务提交时线程池无法处理时的拒绝策略。
-
任务队列(
BlockingQueue):用于存储等待执行的任务,常见的有LinkedBlockingQueue、ArrayBlockingQueue等。 -
拒绝策略:当线程池无法处理新任务时采取的策略,常见的有以下几种:
AbortPolicy:直接抛出RejectedExecutionException异常。CallerRunsPolicy:在调用者线程中执行任务。DiscardPolicy:默默丢弃无法处理的任务。DiscardOldestPolicy:丢弃队列中最旧的任务,并尝试重新提交新任务。
三、Java 线程池的使用方法
-
创建线程池:
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadPoolExecutor; public class ThreadPoolExample { public static void main(String[] args) { // 创建一个固定大小的线程池,包含 5 个线程 ExecutorService executorService = Executors.newFixedThreadPool(5); ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executorService; for (int i = 0; i < 10; i++) { Runnable task = () -> { System.out.println("Task " + Thread.currentThread().getName() + " is running."); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } }; executorService.execute(task); } // 查看线程池的一些信息 System.out.println("Core pool size: " + threadPoolExecutor.getCorePoolSize()); System.out.println("Maximum pool size: " + threadPoolExecutor.getMaximumPoolSize()); System.out.println("Number of threads: " + threadPoolExecutor.getPoolSize()); System.out.println("Number of active threads: " + threadPoolExecutor.getActiveCount()); executorService.shutdown(); } } -
自定义线程池:
import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class CustomThreadPoolExample { public static void main(String[] args) { // 创建自定义线程池 BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(10); ThreadPoolExecutor executor = new ThreadPoolExecutor( 3, 5, 10, TimeUnit.SECONDS, queue); for (int i = 0; i < 15; i++) { Runnable task = () -> { System.out.println("Task " + Thread.currentThread().getName() + " is running."); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } }; executor.execute(task); } executor.shutdown(); } }
四、结合 Spring Boot 使用线程池
-
配置线程池:
- 在 Spring Boot 中,可以通过配置类来创建和配置线程池。
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.concurrent.Executor; @Configuration public class ThreadPoolConfig { @Bean public Executor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(5); executor.setMaxPoolSize(10); executor.setQueueCapacity(20); executor.setThreadNamePrefix("my-thread-"); executor.initialize(); return executor; } } -
使用线程池:
- 在需要执行异步任务的地方注入线程池,并使用它来执行任务。
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; @Service public class MyService { @Autowired private java.util.concurrent.Executor taskExecutor; public void doAsyncTask() { taskExecutor.execute(() -> { // 异步任务的代码 System.out.println("Async task is running."); }); } }

浙公网安备 33010602011771号