java 怎么把两个线程
- 后端开发
- 2025-08-07
- 4
Thread
对象或实现
Runnable
接口的类
Java中,有多种方法可以将两个线程进行关联或同步,常见的方式包括使用Thread
类、Runnable
接口、Callable
接口以及ExecutorService
等,下面将详细介绍几种常见的方法,并通过示例代码进行说明。
使用Thread
类创建并启动两个线程
Thread
类是Java中用于表示线程的类,可以通过继承Thread
类并重写run()
方法来定义线程的执行逻辑,以下是一个简单的示例,展示如何创建并启动两个线程:
public class TwoThreadsExample extends Thread { private String threadName; public TwoThreadsExample(String name) { this.threadName = name; } @Override public void run() { System.out.println(threadName + " is running."); // 模拟一些工作 for (int i = 0; i < 5; i++) { System.out.println(threadName + ": " + i); try { Thread.sleep(500); // 暂停半秒 } catch (InterruptedException e) { System.out.println(threadName + " was interrupted."); } } System.out.println(threadName + " has finished."); } public static void main(String[] args) { Thread thread1 = new TwoThreadsExample("Thread-1"); Thread thread2 = new TwoThreadsExample("Thread-2"); thread1.start(); thread2.start(); } }
输出示例:
Thread-1 is running.
Thread-2 is running.
Thread-1: 0
Thread-2: 0
Thread-1: 1
Thread-2: 1
...
Thread-1 has finished.
Thread-2 has finished.
使用Runnable
接口创建并启动两个线程
Runnable
接口提供了另一种定义线程任务的方式,通过实现Runnable
接口的run()
方法,可以将其传递给Thread
对象来启动线程。
public class RunnableTwoThreads implements Runnable { private String threadName; public RunnableTwoThreads(String name) { this.threadName = name; } @Override public void run() { System.out.println(threadName + " is running."); for (int i = 0; i < 5; i++) { System.out.println(threadName + ": " + i); try { Thread.sleep(500); } catch (InterruptedException e) { System.out.println(threadName + " was interrupted."); } } System.out.println(threadName + " has finished."); } public static void main(String[] args) { Runnable task1 = new RunnableTwoThreads("Runnable-Thread-1"); Runnable task2 = new RunnableTwoThreads("Runnable-Thread-2"); Thread thread1 = new Thread(task1); Thread thread2 = new Thread(task2); thread1.start(); thread2.start(); } }
使用Callable
和Future
获取线程返回值
如果需要在线程执行完成后获取结果,可以使用Callable
接口和Future
对象。Callable
接口的call()
方法可以返回一个结果,并且可以抛出异常。
import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; public class CallableTwoThreads implements Callable<Integer> { private String threadName; public CallableTwoThreads(String name) { this.threadName = name; } @Override public Integer call() throws Exception { System.out.println(threadName + " is running."); int sum = 0; for (int i = 0; i < 5; i++) { System.out.println(threadName + ": " + i); sum += i; Thread.sleep(500); } System.out.println(threadName + " has finished."); return sum; } public static void main(String[] args) { CallableTwoThreads task1 = new CallableTwoThreads("Callable-Thread-1"); CallableTwoThreads task2 = new CallableTwoThreads("Callable-Thread-2"); FutureTask<Integer> future1 = new FutureTask<>(task1); FutureTask<Integer> future2 = new FutureTask<>(task2); Thread thread1 = new Thread(future1); Thread thread2 = new Thread(future2); thread1.start(); thread2.start(); try { System.out.println("Result from Thread-1: " + future1.get()); System.out.println("Result from Thread-2: " + future2.get()); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } }
使用ExecutorService
管理线程池
ExecutorService
是Java并发库中用于管理线程池的接口,可以方便地提交任务并控制线程的生命周期,以下示例展示了如何使用ExecutorService
来执行两个线程任务。
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ExecutorServiceTwoThreads implements Runnable { private String threadName; public ExecutorServiceTwoThreads(String name) { this.threadName = name; } @Override public void run() { System.out.println(threadName + " is running."); for (int i = 0; i < 5; i++) { System.out.println(threadName + ": " + i); try { Thread.sleep(500); } catch (InterruptedException e) { System.out.println(threadName + " was interrupted."); } } System.out.println(threadName + " has finished."); } public static void main(String[] args) { ExecutorService executor = Executors.newFixedThreadPool(2); executor.submit(new ExecutorServiceTwoThreads("Executor-Thread-1")); executor.submit(new ExecutorServiceTwoThreads("Executor-Thread-2")); executor.shutdown(); } }
线程同步与通信
在多线程环境中,线程之间的同步与通信是非常重要的,Java提供了多种同步机制,如synchronized
关键字、wait()
和notify()
方法、以及Lock
接口等,以下是一个简单的示例,展示两个线程如何通过wait()
和notify()
进行通信。
public class WaitNotifyExample { private static final Object lock = new Object(); private static boolean condition = false; public static void main(String[] args) { Thread thread1 = new Thread(() -> { synchronized (lock) { while (!condition) { try { lock.wait(); } catch (InterruptedException e) { System.out.println("Thread-1 was interrupted."); } } System.out.println("Thread-1: Condition met, proceeding..."); } }); Thread thread2 = new Thread(() -> { synchronized (lock) { System.out.println("Thread-2: Setting condition to true."); condition = true; lock.notify(); } }); thread1.start(); thread2.start(); } }
输出示例:
Thread-1: Condition met, proceeding...
Thread-2: Setting condition to true.
使用CountDownLatch
进行线程同步
CountDownLatch
是一个同步工具类,允许一个或多个线程等待一组其他线程完成操作,以下示例展示了如何使用CountDownLatch
来同步两个线程的启动。
import java.util.concurrent.CountDownLatch; public class CountDownLatchExample { public static void main(String[] args) { CountDownLatch latch = new CountDownLatch(2); // 等待两个线程完成 Thread thread1 = new Thread(() -> { System.out.println("Thread-1 is doing work..."); try { Thread.sleep(1000); // 模拟工作 } catch (InterruptedException e) { System.out.println("Thread-1 was interrupted."); } System.out.println("Thread-1 has finished."); latch.countDown(); // 减少计数 }); Thread thread2 = new Thread(() -> { System.out.println("Thread-2 is doing work..."); try { Thread.sleep(1500); // 模拟工作 } catch (InterruptedException e) { System.out.println("Thread-2 was interrupted."); } System.out.println("Thread-2 has finished."); latch.countDown(); // 减少计数 }); thread1.start(); thread2.start(); try { latch.await(); // 等待计数为0 System.out.println("Both threads have finished. Proceeding..."); } catch (InterruptedException e) { System.out.println("Main thread was interrupted."); } } }
输出示例:
Thread-1 is doing work...
Thread-2 is doing work...
Thread-1 has finished.
Thread-2 has finished.
Both threads have finished. Proceeding...
使用表格归纳不同方法的特点
方法 | 描述 | 优点 | 缺点 |
---|---|---|---|
Thread 类 |
通过继承Thread 类并重写run() 方法来定义线程 |
简单直接,适用于简单的线程任务 | 不适合共享代码,每个线程需要单独定义 |
Runnable 接口 |
实现Runnable 接口的run() 方法,并传递给Thread 对象启动 |
更灵活,允许多个线程共享同一个Runnable 实例 |
不能直接返回结果,需要使用Callable 或其它机制 |
Callable 接口 |
实现Callable 接口的call() 方法,可以返回结果,并可能抛出异常 |
可以获取线程执行结果,适用于需要返回值的任务 | 相对复杂,需要处理Future 对象 |
ExecutorService |
使用线程池管理线程,通过提交任务来执行 | 高效管理线程资源,适用于大量短生命周期的线程任务 | 需要了解线程池的配置和使用 |
synchronized 关键字 |
用于保证同一时刻只有一个线程可以访问某段代码或某个对象 | 简单易用,适用于基本的同步需求 | 可能导致性能瓶颈,特别是在高并发环境下 |
CountDownLatch |
允许一个或多个线程等待其他线程完成特定操作后再继续执行 | 灵活控制线程启动顺序,适用于需要等待多个线程完成的场景 | 需要正确设置计数,否则可能导致死锁 |
wait() 和notify() |
用于线程间的通信,控制线程的等待和唤醒 | 精确控制线程间的协作,适用于复杂的同步场景 | 容易出错,需谨慎使用,避免死锁和通知丢失 |
FAQs
问题1:如何在Java中创建一个返回结果的线程?
答:在Java中,如果需要创建一个能够返回结果的线程,可以使用Callable
接口和Future
对象,通过实现Callable
接口的call()
方法,可以在线程执行完成后返回一个结果,将Callable
任务提交给ExecutorService
,并通过Future
对象获取结果。
Callable<Integer> task = () -> { // 执行一些计算或任务 return result; }; ExecutorService executor = Executors.newSingleThreadExecutor(); Future<Integer> future = executor.submit(task); Integer result = future.get(); // 获取结果 executor.shutdown();
问题2:什么是线程池,为什么要使用线程池?
答:线程池是一种基于池化技术的资源管理方式,用于管理和复用一定数量的线程,通过线程池,可以有效地控制线程的创建和销毁,减少系统资源的消耗,提高应用程序的性能和响应速度,使用线程池的主要优点包括:
- 资源复用:线程池中的线程可以被重复使用,避免了频繁创建和销毁线程带来的开销。
- 性能提升:通过合理配置线程池的大小,可以提高系统的并发处理能力,减少任务的等待时间。