主页 > 其他  > 

线程的多种创建方式和使用

线程的多种创建方式和使用
一、线程的多种创建方式

在 Java 中,创建线程有多种方式,每种方式都有其特定的应用场景。以下是 Java 中常用的几种创建线程的方式,以及它们的具体实现:

1、通过继承 Thread 类创建线程

Java 中的 Thread 类提供了一个可执行的线程对象。通过继承 Thread 类并重写其 run() 方法来定义线程的执行体。

示例代码1: class MyThread extends Thread { @Override public void run() { // 线程要执行的代码 System.out.println("Thread is running"); } } public class ThreadExample { public static void main(String[] args) { MyThread thread = new MyThread(); // 创建线程对象 thread.start(); // 启动线程 } } 示例代码2:使用匿名内部类 public class AnonymousThreadExample { public static void main(String[] args) { // 创建线程并通过匿名内部类继承 Thread 类 Thread thread = new Thread() { @Override public void run() { // 线程要执行的代码 System.out.println("Thread is running using Anonymous Thread"); } }; thread.start(); // 启动线程 } } 说明: 优点:简单直接,适用于简单的线程创建。缺点:Java 中类只能继承一个类,因此如果已经继承了其他类,不能再继承 Thread 类。 2、通过实现 Runnable 接口创建线程

实现 Runnable 接口是一种更加灵活的方式,它可以避免 Java 单继承的限制。通过实现 Runnable 接口的 run() 方法来定义线程的执行体,再通过 Thread 类来启动该线程。

示例代码: class MyRunnable implements Runnable { @Override public void run() { // 线程要执行的代码 System.out.println("Thread is running"); } } public class RunnableExample { public static void main(String[] args) { MyRunnable myRunnable = new MyRunnable(); // 创建 Runnable 实现类对象 Thread thread = new Thread(myRunnable); // 将 Runnable 实现类传递给 Thread thread.start(); // 启动线程 } } 说明: 优点:比继承 Thread 更灵活,可以同时继承其他类。适用于多线程共享同一资源的情况。缺点:需要通过 Thread 对象来启动线程,不能直接调用 start() 方法。 3、通过实现 Callable 接口创建线程(可返回值)

Callable 接口与 Runnable 类似,但它允许任务执行时返回结果,可以处理异常。通常与 ExecutorService 配合使用,能够提交任务并获得执行结果。

示例代码: import java.util.concurrent.*; class MyCallable implements Callable<String> { @Override public String call() throws Exception { // 线程要执行的代码 return "Thread is running and returning result"; } } public class CallableExample { public static void main(String[] args) throws ExecutionException, InterruptedException { MyCallable myCallable = new MyCallable(); ExecutorService executorService = Executors.newCachedThreadPool(); // 创建线程池 Future<String> future = executorService.submit(myCallable); // 提交任务 String result = future.get(); // 获取任务的执行结果 System.out.println(result); // 输出结果 executorService.shutdown(); // 关闭线程池 } } 说明: 优点:能够返回任务执行结果,适用于需要计算并返回结果的场景。缺点:需要使用 ExecutorService 来执行任务,相比 Runnable 略显复杂。 4、通过 ExecutorService 创建线程池

线程池是一种管理线程的方式,通过 ExecutorService 可以创建线程池并提交任务,线程池会自动管理线程的创建、销毁和复用。通过线程池可以有效地管理多线程任务,避免频繁的线程创建销毁操作。

示例代码: import java.util.concurrent.*; class MyTask implements Runnable { @Override public void run() { System.out.println("Thread is running from ExecutorService"); } } public class ExecutorServiceExample { public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(3); // 创建固定大小的线程池 for (int i = 0; i < 5; i++) { executorService.submit(new MyTask()); // 提交任务给线程池 } executorService.shutdown(); // 关闭线程池 } } 说明: 优点:可以管理大量线程,自动复用线程,提高性能。适用于高并发的场景。缺点:需要额外的线程池管理,使用稍微复杂。 5、通过 ForkJoinPool 创建线程(适用于分治任务)

ForkJoinPool 是一种专门用于处理大规模并行任务的线程池,特别适合分治型任务的执行。它通过将任务分割为多个子任务并行执行来提高性能。

示例代码: import java.util.concurrent.*; class MyForkJoinTask extends RecursiveTask<Integer> { @Override protected Integer compute() { // 线程要执行的代码 return 1; // 示例返回值 } } public class ForkJoinPoolExample { public static void main(String[] args) { ForkJoinPool forkJoinPool = new ForkJoinPool(); // 创建 ForkJoinPool MyForkJoinTask task = new MyForkJoinTask(); ForkJoinTask<Integer> result = forkJoinPool.submit(task); // 提交任务 System.out.println("Result: " + result.join()); // 获取结果 forkJoinPool.shutdown(); // 关闭线程池 } } 说明: 优点:适合计算密集型任务和分治型任务,能够有效处理大量子任务。缺点:相对于其他线程池,使用场景更为特殊。 6、通过 Lambda 表达式创建线程(简化代码)

Java 8 引入了 Lambda 表达式,可以简化线程的创建过程。通常与 Runnable 接口配合使用,能够在一行代码中定义线程的执行内容。

示例代码: public class LambdaThreadExample { public static void main(String[] args) { // 使用 Lambda 表达式创建线程 Thread thread = new Thread(() -> { System.out.println("Thread is running using Lambda"); }); thread.start(); // 启动线程 } } 说明: 优点:代码简洁,减少了冗长的类定义,适用于快速创建简单线程。缺点:仅适用于 Runnable 接口场景,对于其他接口无法使用。
7、总结

Java 提供了多种方式来创建线程,每种方式都有其特定的优势和适用场景:

继承 Thread 类:适合简单的线程创建,但不能继承其他类。实现 Runnable 接口:适合多线程共享资源的情况,比继承 Thread 更灵活。实现 Callable 接口:适合需要返回结果的线程任务,通常与 ExecutorService 配合使用。使用 ExecutorService:适合管理大量线程,自动复用线程,提高系统性能。使用 ForkJoinPool:适合大规模并行计算和分治型任务。使用 Lambda 表达式:适合快速创建简单线程,代码简洁。

选择哪种方式,取决于具体应用场景和任务需求。在实际开发中,通常推荐使用 ExecutorService 或 ForkJoinPool 来管理线程,以提高代码的可维护性和性能。

二、Thread类最常用个方法 1. start()

功能:启动一个新线程,使其进入就绪状态,等待操作系统调度执行。

作用:启动线程后,JVM 会自动调用 run() 方法,并在新的线程中执行。注意:线程一旦启动后,不能再次启动。如果调用 start() 方法多次,会抛出 IllegalThreadStateException 异常。 Thread thread = new Thread(() -> System.out.println("Thread is running")); thread.start(); // 启动线程
2. run()

功能:线程的执行体方法,定义线程启动后要执行的代码。

作用:当调用 start() 启动线程时,JVM 会调用 run() 方法。通常情况下,run() 方法会被覆盖,定义线程的具体执行逻辑。注意:直接调用 run() 方法只是将 run() 方法作为普通方法调用,并不会启动新的线程,仍然是在主线程中执行。 @Override public void run() { System.out.println("Thread is running"); }
3. sleep(long millis)

功能:让当前线程暂停指定时间(以毫秒为单位),进入 休眠状态,不会占用 CPU 资源。

作用:使当前线程暂时进入休眠状态,休眠结束后,线程会回到就绪状态,等待操作系统调度。注意:sleep() 方法是静态的,作用于调用它的当前线程,且可以抛出 InterruptedException 异常。 try { Thread.sleep(1000); // 当前线程暂停 1000 毫秒(1秒) } catch (InterruptedException e) { e.printStackTrace(); }
4. join()

功能:使当前线程等待目标线程完成后再继续执行,常用于 线程同步。

作用:join() 方法会使当前线程等待调用它的线程(即目标线程)执行完毕后再继续执行。注意:可以指定等待时间,等待超时后 join() 方法会返回。 // 创建子线程对象 Thread thread = new Thread(() -> System.out.println("Thread is running")); // 执行子线程 thread.start(); try { thread.join(); // 当前线程(即:主线程)等待子线程执行完 } catch (InterruptedException e) { e.printStackTrace(); }
5. interrupt()

功能:中断一个线程,设置线程的中断标志为 true,通知线程终止。

作用:如果线程正在执行 sleep()、wait() 或 join() 等阻塞操作,interrupt() 会使这些操作抛出 InterruptedException,从而让线程终止或者退出阻塞。注意:interrupt() 只是设置线程的中断标志,不会立即停止线程的执行。线程需要在合适的地方自行判断 Thread.interrupted() 或捕获 InterruptedException 来响应中断。 Thread thread = new Thread(() -> { try { Thread.sleep(5000); } catch (InterruptedException e) { System.out.println("Thread was interrupted"); } }); thread.start(); thread.interrupt(); // 中断线程
6. isAlive()

功能:判断线程是否已经启动并正在执行。

作用:返回线程是否处于活动状态。如果线程处于 新建状态 或 已死亡状态,返回 false;否则返回 true。 Thread thread = new Thread(() -> System.out.println("Thread is running")); thread.start(); System.out.println(thread.isAlive()); // true
7. getName()

功能:获取线程的名称。

作用:返回当前线程的名字,通常是由 JVM 自动分配的,如 Thread-0、Thread-1 等,也可以手动通过 setName() 方法来设置。 Thread thread = new Thread(() -> System.out.println(Thread.currentThread().getName())); thread.start(); // 输出:Thread-0
8. setName(String name)

功能:设置线程的名称。

作用:给当前线程指定一个名称。为线程设置名称有助于在调试和日志中跟踪线程。 Thread thread = new Thread(() -> System.out.println(Thread.currentThread().getName())); thread.setName("CustomThread"); thread.start(); // 输出:CustomThread
9. getId()

功能:获取线程的唯一标识符。

作用:返回当前线程的唯一 ID,通常用于调试和标识线程。 Thread thread = new Thread(() -> System.out.println(Thread.currentThread().getId())); thread.start(); // 输出线程的 ID,例如:1
10. setPriority(int priority)

功能:设置线程的优先级,影响线程获取 CPU 时间片的频率。

作用:setPriority() 方法允许你设置线程的优先级(从 1 到 10,默认值为 5)。高优先级线程通常会更早地获得 CPU 时间片,但这也依赖于操作系统的线程调度策略。 Thread thread = new Thread(() -> System.out.println("Thread is running")); thread.setPriority(Thread.MAX_PRIORITY); // 设置为最高优先级 thread.start();
11. yield()

功能:使当前线程放弃 CPU 时间片,暂时让出 CPU 资源,允许其他线程执行。

作用:yield() 是一个静态方法,当前线程会让出 CPU 使用权,但是不会完全让出控制权,仍然可以继续执行。具体行为依赖于操作系统的线程调度策略。 Thread.yield(); // 当前线程暂停,让出 CPU 资源
12. currentThread()

功能:获取当前正在执行的线程对象。

作用:返回代表当前正在执行线程的 Thread 对象。常用于获取当前线程的状态、名称等信息。 Thread current = Thread.currentThread(); System.out.println(current.getName()); // 输出当前线程的名称
三. 线程的生命周期
标签:

线程的多种创建方式和使用由讯客互联其他栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“线程的多种创建方式和使用