Java线程基础
线程的概念
在Java中,线程是程序执行的最小单元。它允许我们将复杂的任务划分成多个子任务并发执行,以提高应用程序的响应速度和性能。每一个线程都有自己独立的运行栈和程序计数器,线程在操作系统中可以看作是轻量级的进程。
线程与进程的区别
线程和进程是计算机程序并行执行的基本单元。进程有自己独立的地址空间,而所有线程共享进程的地址空间和资源。线程之间的通信和数据交换成本较低,这意味着多线程程序比多进程程序更高效。
Java多线程编程
创建线程的优势
使用多线程,可以在同一程序中并行执行多个操作,尤其是在进行I/O操作或进行复杂计算时。多线程可以有效地利用CPU资源,尤其是在多核CPU上。
实际场景中的多线程应用示例
设想一个服务器应用程序,需要同时处理成百上千的客户端请求。如果串行处理这些请求,那么当服务器处理前面的请求时,后面的请求必须等待,这会导致严重的响应延迟。通过使用多线程,每个请求可以在单独的线程中几乎同时进行处理,显著提升服务的吞吐量和响应时间。
线程的实现方式
继承Thread类
在Java中,创建线程的最直接方式就是继承Thread类,然后重写其run方法。当调用线程的start方法时,会新开启一个线程并执行run方法中的代码。
代码示例
public class MyThread extends Thread {
@Override
public void run() {
// 线程执行的操作
System.out.println("Thread running via MyThread class.");
}
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start(); // 开启线程
}
}
实现Runnable接口
实现Runnable接口是另一种创建线程的方式。这种方式更灵活,因为它允许类继承其他类的同时,还能实现多线程的功能。
代码示例
public class MyRunnable implements Runnable {
@Override
public void run() {
// 线程执行的操作
System.out.println("Thread running via MyRunnable implementation.");
}
public static void main(String[] args) {
Thread thread = new Thread(new MyRunnable());
thread.start(); // 开启线程
}
}
实现Callable接口
如果您希望线程执行完毕后能返回值,您可以实现Callable接口。Callable接口的call方法允许返回值,并且可以抛出异常。
代码示例
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class MyCallable implements Callable<Integer> {
@Override
public Integer call() {
// 线程执行的操作
System.out.println("Thread running via MyCallable implementation.");
return 123; // 返回值
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<Integer> futureTask = new FutureTask<>(new MyCallable());
Thread thread = new Thread(futureTask);
thread.start(); // 开启线程
// 获取Callable线程的返回值
Integer result = futureTask.get();
System.out.println("Result from MyCallable: " + result);
}
}
线程的生命周期
线程状态详解
Java线程有五种基本状态:新建(NEW)、可运行(RUNNABLE)、阻塞(BLOCKED)、等待(WAITING)、计时等待(TIMED_WAITING)和终止(TERMINATED)。
线程状态转换图(PlantUML图)
下面我们使用PlantUML来描述这些状态以及它们之间的转换:
生命周期相关的方法
Java提供了一系列方法来控制线程的生命周期,比如start(), join(), wait(), notify(), sleep(), 等等。
代码示例
public class ThreadLifeCycleExample {
private static final Object LOCK = new Object();
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(() -> {
synchronized(LOCK) {
try {
System.out.println("Thread1 is WAITING.");
LOCK.wait(); // 线程进入WAITING状态
} catch(InterruptedException e) {
Thread.currentThread().interrupt(); // 处理中断
}
System.out.println("Thread1 is RUNNABLE again.");
}
});
Thread thread2 = new Thread(() -> {
synchronized(LOCK) {
System.out.println("Thread2 is RUNNABLE and will notify Thread1.");
LOCK.notifyAll(); // 通知正在LOCK上等待的线程
}
});
thread1.start();
Thread.sleep(100); // 确保thread1先运行
thread2.start();
}
}
Java线程池
线程池的概念及优势
线程池(Thread Pool)是一种基于池化技术的线程使用方式,它可以管理和复用多个线程,减少线程创建和销毁所带来的开销。线程池不仅减少了资源消耗,还可以提高响应速度、提高线程的可管理性。
常见线程池类型
Java中的java.util.concurrent包提供了多种线程池,包括FixedThreadPool(固定大小线程池)、CachedThreadPool(可缓存线程池)、SingleThreadExecutor(单线程化的线程池)、以及ScheduledThreadPool(定时任务线程池)。
线程池参数详解
线程池创建时可以指定多种参数,比如核心线程数(corePoolSize)、最大线程数(maximumPoolSize)、存活时间(keepAliveTime)、工作队列(workQueue)等等,这些参数共同决定了线程池的行为。
代码示例
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExample {
public static void main(String[] args) {
// 创建固定大小的线程池
ExecutorService executorService = Executors.newFixedThreadPool(4);
for(int i = 0; i < 10; i++) {
int taskNumber = i;
executorService.submit(() -> {
// 线程池中的线程执行的任务
System.out.println("Executing task " + taskNumber +
" on thread " + Thread.currentThread().getName());
});
}
executorService.shutdown(); // 关闭线程池
try {
// 等待线程池中的所有任务完成
if (!executorService.awaitTermination(800, TimeUnit.MILLISECONDS)) {
executorService.shutdownNow();
}
} catch (InterruptedException e) {
executorService.shutdownNow();
}
}
}
Java线程池进阶
自定义线程池
对于特定的应用需求,内置的线程池可能不够用。这时,你可以通过ThreadPoolExecutor来创建自定义线程池,它提供了更加灵活的配置选项。
代码示例
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class CustomThreadPoolExample {
public static void main(String[] args) {
// 自定义线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, // 核心线程数
4, // 最大线程数
100, // 线程没有任务执行时最多保持多久时间会终止
TimeUnit.MILLISECONDS, // 时间单位
new ArrayBlockingQueue<>(2), // 任务队列
new ThreadPoolExecutor.DiscardOldestPolicy() // 饱和策略
);
for (int i = 0; i < 5; i++) {
int taskNumber = i;
executor.submit(() -> {
System.out.println("Executing task " + taskNumber);
});
}
executor.shutdown();
}
}
Fork/Join框架解读
Fork/Join框架是Java 7引入的一种用于并行执行任务的机制,它是建立在工作窃取算法之上,特别适合处理可以递归划分的任务。
代码示例
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;
public class ForkJoinExample extends RecursiveTask<Integer> {
private final int[] numbers;
private final int start;
private final int end;
public ForkJoinExample(int[] numbers, int start, int end) {
this.numbers = numbers;
this.start = start;
this.end = end;
}
@Override
protected Integer compute() {
int length = end - start;
if (length <= 2) {
return computeDirectly();
} else {
int split = length / 2;
ForkJoinExample left = new ForkJoinExample(numbers, start, start + split);
ForkJoinExample right = new ForkJoinExample(numbers, start + split, end);
invokeAll(left, right);
return left.join() + right.join();
}
}
private Integer computeDirectly() {
int sum = 0;
for (int i = start; i < end; i++) {
sum += numbers[i];
}
return sum;
}
public static void main(String[] args) {
ForkJoinPool pool = new ForkJoinPool();
int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
ForkJoinExample task = new ForkJoinExample(numbers, 0, numbers.length);
int result = pool.invoke(task);
System.out.println("Result: " + result);
}
}