Java 线程对比(Thread,Runnable,Callable)实例详解
介绍
Java线程(Thread)是Java程序中运行的最小单元,是实现并发编程的基础。在Java中,创建线程一般有三种方式:继承Thread类、实现Runnable接口和实现Callable接口。本文将对这三种方式进行详细比较,并提供示例说明。
Thread类
继承Thread类是Java创建线程最原始的方式。这种方式需要重写Thread类的run方法,在run方法中编写线程要执行的代码。示例代码如下:
public class MyThread extends Thread {
@Override
public void run() {
// 线程要执行的代码
}
}
// 创建线程
MyThread thread = new MyThread();
// 启动线程
thread.start();
这种方式简单粗暴,但实现起来较为繁琐,因为Java只允许单继承,如果要扩展其他类,则不能使用此方式。
Runnable接口
实现Runnable接口是Java创建线程的常见方式,由于Java中可以实现多个接口,因此这种方式具有较高的灵活性。Runnable接口只有一个run方法,需要在线程中重写run方法,在run方法中编写线程要执行的代码。示例代码如下:
public class MyRunnable implements Runnable {
@Override
public void run() {
// 线程要执行的代码
}
}
// 创建线程
Thread thread = new Thread(new MyRunnable());
// 启动线程
thread.start();
可以看出,与继承Thread类相比,实现Runnable接口更具有可扩展性。此外,使用Runnable方式还可以将线程的代码和线程独立开来,便于重用。
Callable接口
在JDK5.0之后,Java引入了Callable接口,它和Runnable接口类似,也是一个可以在线程中执行的任务,但是它可以返回执行结果。Callable接口的实现类必须通过FutureTask包装器线程才能执行。示例代码如下:
public class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
// 线程要执行的代码
return 线程执行结果;
}
}
// 创建线程
FutureTask<Integer> futureTask = new FutureTask<>(new MyCallable());
Thread thread = new Thread(futureTask);
// 启动线程
thread.start();
// 获取线程执行结果
Integer result = futureTask.get();
和Runnable接口相比,Callable接口可以返回线程执行结果,适用于需要返回结果的线程。
示例说明
示例一:使用Runnable接口实现多线程下载文件
public class DownloadFile implements Runnable {
private String url;
private String fileName;
private int startIndex;
private int endIndex;
public DownloadFile(String url, String fileName, int startIndex, int endIndex) {
this.url = url;
this.fileName = fileName;
this.startIndex = startIndex;
this.endIndex = endIndex;
}
@Override
public void run() {
try {
URL url = new URL(this.url);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Range", "bytes=" + this.startIndex + "-" + this.endIndex);
InputStream inStream = conn.getInputStream();
RandomAccessFile file = new RandomAccessFile(this.fileName, "rw");
file.seek(this.startIndex);
byte[] buffer = new byte[1024];
int length = 0;
while ((length = inStream.read(buffer)) != -1) {
file.write(buffer, 0, length);
}
file.close();
inStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class Main {
public static void main(String[] args) {
String url = "https://example.com/file.zip";
String fileName = "file.zip";
int threadCount = 4;
try {
URL fileUrl = new URL(url);
HttpURLConnection conn = (HttpURLConnection) fileUrl.openConnection();
int fileSize = conn.getContentLength();
conn.disconnect();
int blockSize = fileSize / threadCount;
for (int i = 0; i < threadCount; i++) {
int startIndex = i * blockSize;
int endIndex = (i + 1) * blockSize - 1;
if (i == threadCount - 1) {
endIndex = fileSize - 1;
}
new Thread(new DownloadFile(url, fileName, startIndex, endIndex)).start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
本示例中,使用Runnable接口实现了多线程下载文件。通过获取文件大小,将文件分成多块,通过多个线程同时下载,从而提高了下载速度。
示例二:使用Callable接口实现多线程计算
public class Calculator implements Callable<Integer> {
private int start;
private int end;
public Calculator(int start, int end) {
this.start = start;
this.end = end;
}
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = start; i <= end; i++) {
sum += i;
}
return sum;
}
}
public class Main {
public static void main(String[] args) {
int start = 1;
int end = 100;
int threadCount = 4;
int sum = 0;
try {
ExecutorService executorService = Executors.newFixedThreadPool(threadCount);
List<Future<Integer>> futures = new ArrayList<>();
int blockSize = (end - start + 1) / threadCount;
for (int i = 0; i < threadCount; i++) {
int startIndex = start + i * blockSize;
int endIndex = startIndex + blockSize - 1;
if (i == threadCount - 1) {
endIndex = end;
}
Callable<Integer> callable = new Calculator(startIndex, endIndex);
Future<Integer> future = executorService.submit(callable);
futures.add(future);
}
for (Future<Integer> future : futures) {
sum += future.get();
}
executorService.shutdown();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("1-100的和为:" + sum);
}
}
本示例中,使用Callable接口实现了多线程计算1-100之间所有数的和。将任务拆分成多个子任务,通过线程池执行,最终将子任务的结果合并,从而提高了计算速度。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java 线程对比(Thread,Runnable,Callable)实例详解 - Python技术站