Java并发编程之常用的多线程实现方式分析
1. 前言
在 Java 程序中,多线程编程已经成为了很常见的一种编程方式,因为这能够很好地提高程序的效率。在进行 Java 多线程编程的时候,我们需要了解常用的多线程实现方式,这样才能更好地开发出高效可靠的多线程应用。本文将分析 Java 常用的多线程实现方式。
2. 继承 Thread 类
继承 Thread 类是最常见的实现多线程的方式。下面是一个继承 Thread 类的示例代码:
public class MyThread extends Thread {
public void run() {
// 线程代码
}
}
在上面的代码中,我们继承了 Thread 类,并重写了 run() 方法,可以在 run() 方法中写入线程要执行的代码。需要注意的是,start() 方法会启动该线程,当 run() 方法结束时,该线程就会被销毁。
使用该方法有以下缺点:
- 使用继承的方式将 Thread 与 业务代码 绑定在了一起,不利于程序的扩展和维护
- Java 不支持多重继承,如果这个类已经有父类了,那么使用这种方式就不可行了
3. 实现 Runnable 接口
实现 Runnable 接口是 Java 程序中另一种常见的实现多线程的方式。下面是一个实现 Runnable 接口的示例代码:
public class MyRunnable implements Runnable {
public void run() {
// 线程代码
}
}
在上面的代码中,我们实现了 Runnable 接口,并重写了 run() 方法,同样可以在 run() 方法中写入线程要执行的代码。需要注意的是,该方式最终还是要用 Thread 类来包装一下,才能启动这个线程。
使用该方法有以下优点:
- Java 支持实现多个接口,因此即使这个类已经有父类了,也不会有问题
- 允许线程类和实现线程 Runnable 接口的业务代码解耦,这样更方便程序的扩展和维护
4. 使用 Callable 和 Future 接口
Callable 和 Future 接口是 Java 1.5 引进的新特性,使用这种方式可以方便地获取线程执行的返回值。下面是一个实现 Callable 接口的示例代码:
public class MyCallable implements Callable<String> {
public String call() throws Exception {
// 线程代码
return "执行完线程代码后,返回的结果";
}
}
在上面的代码中,我们实现了 Callable 接口,并重写了 call() 方法,该方法返回的是一个泛型类型的结果,和 Runnable 接口原来的 run() 方法不一样。需要注意的是,需要使用 Future 接口的 get() 方法来获取线程执行完毕后的返回值。
使用该方法有以下优点:
- 可以方便地获取线程执行的返回值
- 允许和业务代码解耦,方便程序的扩展和维护
5. 使用线程池
Java 5 引入了 Executor 框架,使多线程编程变得更简单和方便。可以通过 newFixedThreadPool() 方法来创建一个固定大小的线程池,然后提交 Runnable 或 Callable 任务给线程池,该线程池会以线程池中的线程去执行任务。下面是一个使用线程池的示例代码:
public class ThreadPoolExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(5);
Runnable worker = new MyRunnable();
executor.execute(worker);
Callable<String> callable = new MyCallable();
Future<String> future = executor.submit(callable);
executor.shutdown();
}
}
在上面的代码中,我们使用了 Executors 提供的静态方法 newFixedThreadPool() 来获取一个线程池,该线程池有 5 个固定大小的线程。然后将 Runnable 和 Callable 任务提交到该线程池中,最后通过 shutdown() 方法关闭该线程池。
6. ThreadLocal
ThreadLocal 是 Java 中一种特殊的变量,它的值只能被当前线程读写,其他线程则不能访问。在多线程编程中,可以使用 ThreadLocal 来存储线程本地变量,从而避免线程并发的问题。下面是一个使用 ThreadLocal 的示例代码:
public class MyThreadLocal {
public static final ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() {
protected Integer initialValue() {
return new Integer(0);
}
};
public Integer getNextValue() {
Integer value = threadLocal.get() + 1;
threadLocal.set(value);
return value;
}
}
在上面的代码中,我们定义了一个 ThreadLocal 类型的 threadLocal 变量,通过 get() 方法获取该变量的值,通过 set() 方法设置该变量的值。需要注意的是,每个线程都有自己的变量值,互相之间不会产生影响。
7. Conclusion
本文介绍了 Java 常用的多线程实现方式,包括继承 Thread 类、实现 Runnable 接口、使用 Callable 和 Future 接口、使用线程池、ThreadLocal 等。希望能对Java 多线程编程有所帮助。
两个示例代码:
- MyRunnable 类实现 Runnable 接口的示例代码:
public class MyRunnable implements Runnable {
private String name;
public MyRunnable(String name) {
this.name = name;
}
public void run() {
for(int i = 1; i <= 5; i++) {
System.out.println("线程 " + name + " 执行第 " + i + " 次");
}
}
}
在上面的代码中,我们定义了一个 MyRunnable 类来实现 Runnable 接口,并在 run() 方法中编写线程要执行的代码。该类的作用是打印出线程执行的次数和线程名称。
- ThreadPoolExample 类使用线程池的示例代码:
public class ThreadPoolExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(2);
Runnable worker1 = new MyRunnable("A");
Runnable worker2 = new MyRunnable("B");
executor.execute(worker1);
executor.execute(worker2);
executor.shutdown();
}
}
在上面的代码中,我们创建了一个线程池 executor,并使用 Executors 提供的静态方法 newFixedThreadPool() 来获取一个固定大小的线程池,该线程池有 2 个固定大小的线程。然后将 Runnable 任务 worker1 和 worker2 提交到该线程池中,最后通过 shutdown() 方法关闭该线程池。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java并发编程之常用的多线程实现方式分析 - Python技术站