Java 编码系列:线程基础与最佳实践

打印 上一主题 下一主题

主题 1029|帖子 1029|积分 3087

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
引言

在多使命处置惩罚和并发编程中,线程是不可或缺的一部门。Java 提供了丰富的线程管理和并发控制机制,使得开发者可以轻松地实现多线程应用。本文将深入探讨 Java 线程的基础知识,包罗 Thread 类、Runnable 接口、Callable 接口以及线程的生命周期,并联合大厂的最佳实践和底层核心原理,帮助读者全面把握这些关键技术。
1. 线程基础

1.1 什么是线程

线程是操纵系统能够进行运算调理的最小单位。它被包含在进程之中,是进程中的现实运作单位。一个进程可以包含多个线程,这些线程共享进程的资源,如内存和文件句柄。
1.2 线程的上风



  • 进步响应速率:通过多线程,可以同时执行多个使命,进步应用步调的响应速率。
  • 资源共享:线程共享进程的资源,减少了资源开销。
  • 简化编程模型:多线程编程模型使得复杂的使命可以分解为多个简单的使命并行执行。
2. 创建线程的方式

2.1 继续 Thread 类

通过继续 Thread 类并重写 run 方法,可以创建一个新的线程。
  1. class MyThread extends Thread {
  2.     @Override
  3.     public void run() {
  4.         System.out.println("线程 " + Thread.currentThread().getName() + " 运行中...");
  5.     }
  6. }
  7. public class ThreadExample {
  8.     public static void main(String[] args) {
  9.         MyThread myThread = new MyThread();
  10.         myThread.start(); // 启动线程
  11.     }
  12. }
复制代码
2.2 实现 Runnable 接口

通过实现 Runnable 接口并实现 run 方法,可以创建一个新的线程。这种方式更加机动,因为一个 Runnable 对象可以被多个线程共享。
  1. class MyRunnable implements Runnable {
  2.     @Override
  3.     public void run() {
  4.         System.out.println("线程 " + Thread.currentThread().getName() + " 运行中...");
  5.     }
  6. }
  7. public class RunnableExample {
  8.     public static void main(String[] args) {
  9.         MyRunnable myRunnable = new MyRunnable();
  10.         Thread thread = new Thread(myRunnable, "MyThread");
  11.         thread.start(); // 启动线程
  12.     }
  13. }
复制代码
2.3 实现 Callable 接口

Callable 接口雷同于 Runnable,但它可以返回一个效果,并且可以抛出异常。Callable 接口通常与 Future 和 ExecutorService 一起使用。
  1. import java.util.concurrent.Callable;
  2. import java.util.concurrent.ExecutionException;
  3. import java.util.concurrent.ExecutorService;
  4. import java.util.concurrent.Executors;
  5. import java.util.concurrent.Future;
  6. class MyCallable implements Callable<Integer> {
  7.     @Override
  8.     public Integer call() throws Exception {
  9.         int sum = 0;
  10.         for (int i = 0; i < 100; i++) {
  11.             sum += i;
  12.         }
  13.         return sum;
  14.     }
  15. }
  16. public class CallableExample {
  17.     public static void main(String[] args) {
  18.         ExecutorService executorService = Executors.newFixedThreadPool(2);
  19.         Future<Integer> future = executorService.submit(new MyCallable());
  20.         try {
  21.             int result = future.get(); // 获取结果
  22.             System.out.println("计算结果: " + result);
  23.         } catch (InterruptedException | ExecutionException e) {
  24.             e.printStackTrace();
  25.         } finally {
  26.             executorService.shutdown(); // 关闭线程池
  27.         }
  28.     }
  29. }
复制代码
3. 线程的生命周期

3.1 线程状态

Java 线程有以下几种状态:


  • New:线程被创建但尚未启动。
  • Runnable:线程正在 JVM 中运行,但可能在等待操纵系统资源。
  • Blocked:线程被壅闭,等待监视器锁。
  • Waiting:线程在等待另一个线程执行特定操纵。
  • Timed Waiting:线程在等待指定的时间。
  • Terminated:线程已退出。
3.2 线程状态转换



  • New -> Runnable:调用 start 方法。
  • Runnable -> Blocked:实行获取已被其他线程持有的锁。
  • Runnable -> Waiting:调用 wait、join 或 LockSupport.park 方法。
  • Runnable -> Timed Waiting:调用 sleep、wait(long)、join(long) 或 LockSupport.parkNanos 方法。
  • Blocked -> Runnable:获取到所需的锁。
  • Waiting -> Runnable:等待的条件满意。
  • Timed Waiting -> Runnable:等待时间到期。
  • Runnable -> Terminated:线程的 run 方法执行完毕或因未捕获的异常而制止。
4. 线程同步

4.1 同步方法

通过在方法上使用 synchronized 关键字,可以确保同一时间只有一个线程可以访问该方法。
  1. public class SynchronizedMethodExample {
  2.     private int count = 0;
  3.     public synchronized void increment() {
  4.         count++;
  5.     }
  6.     public static void main(String[] args) {
  7.         SynchronizedMethodExample example = new SynchronizedMethodExample();
  8.         Thread t1 = new Thread(() -> {
  9.             for (int i = 0; i < 1000; i++) {
  10.                 example.increment();
  11.             }
  12.         });
  13.         Thread t2 = new Thread(() -> {
  14.             for (int i = 0; i < 1000; i++) {
  15.                 example.increment();
  16.             }
  17.         });
  18.         t1.start();
  19.         t2.start();
  20.         try {
  21.             t1.join();
  22.             t2.join();
  23.         } catch (InterruptedException e) {
  24.             e.printStackTrace();
  25.         }
  26.         System.out.println("最终计数: " + example.count);
  27.     }
  28. }
复制代码
4.2 同步代码块

通过在代码块上使用 synchronized 关键字,可以确保同一时间只有一个线程可以访问该代码块。
  1. public class SynchronizedBlockExample {
  2.     private int count = 0;
  3.     private final Object lock = new Object();
  4.     public void increment() {
  5.         synchronized (lock) {
  6.             count++;
  7.         }
  8.     }
  9.     public static void main(String[] args) {
  10.         SynchronizedBlockExample example = new SynchronizedBlockExample();
  11.         Thread t1 = new Thread(() -> {
  12.             for (int i = 0; i < 1000; i++) {
  13.                 example.increment();
  14.             }
  15.         });
  16.         Thread t2 = new Thread(() -> {
  17.             for (int i = 0; i < 1000; i++) {
  18.                 example.increment();
  19.             }
  20.         });
  21.         t1.start();
  22.         t2.start();
  23.         try {
  24.             t1.join();
  25.             t2.join();
  26.         } catch (InterruptedException e) {
  27.             e.printStackTrace();
  28.         }
  29.         System.out.println("最终计数: " + example.count);
  30.     }
  31. }
复制代码
5. 线程间通讯

5.1 wait 和 notify 方法

wait 和 notify 方法用于线程间的通讯。wait 方法使当火线程进入等待状态,notify 方法叫醒一个等待的线程。
  1. public class WaitNotifyExample {
  2.     private final Object lock = new Object();
  3.     private boolean flag = false;
  4.     public void producer() {
  5.         synchronized (lock) {
  6.             while (flag) {
  7.                 try {
  8.                     lock.wait();
  9.                 } catch (InterruptedException e) {
  10.                     e.printStackTrace();
  11.                 }
  12.             }
  13.             // 生产数据
  14.             System.out.println("生产数据");
  15.             flag = true;
  16.             lock.notify();
  17.         }
  18.     }
  19.     public void consumer() {
  20.         synchronized (lock) {
  21.             while (!flag) {
  22.                 try {
  23.                     lock.wait();
  24.                 } catch (InterruptedException e) {
  25.                     e.printStackTrace();
  26.                 }
  27.             }
  28.             // 消费数据
  29.             System.out.println("消费数据");
  30.             flag = false;
  31.             lock.notify();
  32.         }
  33.     }
  34.     public static void main(String[] args) {
  35.         WaitNotifyExample example = new WaitNotifyExample();
  36.         Thread producerThread = new Thread(() -> {
  37.             for (int i = 0; i < 5; i++) {
  38.                 example.producer();
  39.             }
  40.         });
  41.         Thread consumerThread = new Thread(() -> {
  42.             for (int i = 0; i < 5; i++) {
  43.                 example.consumer();
  44.             }
  45.         });
  46.         producerThread.start();
  47.         consumerThread.start();
  48.     }
  49. }
复制代码
6. 线程池

6.1 什么是线程池

线程池是一种多线程处置惩罚形式,处置惩罚过程中将使命添加到队列,然后在创建线程后主动启动这些使命。线程池可以有效控制运行的线程数量,减少创建和烧毁线程的开销。
6.2 创建线程池

Java 提供了 ExecutorService 接口和 Executors 工具类来创建和管理线程池。
  1. import java.util.concurrent.ExecutorService;
  2. import java.util.concurrent.Executors;
  3. public class ThreadPoolExample {
  4.     public static void main(String[] args) {
  5.         ExecutorService executorService = Executors.newFixedThreadPool(2);
  6.         for (int i = 0; i < 5; i++) {
  7.             int taskId = i;
  8.             executorService.execute(() -> {
  9.                 System.out.println("任务 " + taskId + " 在线程 " + Thread.currentThread().getName() + " 上运行");
  10.             });
  11.         }
  12.         executorService.shutdown(); // 关闭线程池
  13.     }
  14. }
复制代码
7. 大厂最佳实践

7.1 阿里巴巴《Java开发手册》



  • 避免滥用线程:公道使用线程池,避免频繁创建和烧毁线程。
  • 同步方法优先:在多线程环境中,优先使用同步方法或同步代码块。
  • 避免死锁:计划线程同步时,避免出现死锁的环境。
7.2 Google Java Style Guide



  • 线程安全:确保多线程环境下的代码是线程安全的。
  • 资源管理:使用 try-with-resources 语句管理资源,确保资源在使用后正确开释。
  • 异常处置惩罚:公道处置惩罚线程中的异常,避免未捕获的异常导致线程制止。
7.3 Oracle 官方文档



  • 线程池:保举使用 ExecutorService 来管理线程池,进步线程的复用率。
  • 线程同步:使用 synchronized 关键字或 ReentrantLock 来实现线程同步。
  • 线程间通讯:使用 wait 和 notify 方法实现线程间的通讯。
8. 底层核心原理

8.1 线程调理



  • 时间片轮转:操纵系统通逾期间片轮转的方式调理线程,每个线程在分配的时间片内运行。
  • 优先级:线程的优先级决定了线程被调理的频率,优先级高的线程更有可能被调理。
8.2 线程同步



  • 锁机制:synchronized 关键字和 ReentrantLock 都是基于锁机制实现的线程同步。
  • 监视器锁:synchronized 关键字使用的是监视器锁(Monitor),每个对象都有一个监视器锁。
8.3 线程间通讯



  • 等待/关照机制:wait 和 notify 方法通过等待/关照机制实现线程间的通讯。
  • 条件变量:Condition 接口提供了更机动的等待/关照机制,可以替代 wait 和 notify。
9. 示例代码

9.1 继续 Thread 类

  1. class MyThread extends Thread {
  2.     @Override
  3.     public void run() {
  4.         System.out.println("线程 " + Thread.currentThread().getName() + " 运行中...");
  5.     }
  6. }
  7. public class ThreadExample {
  8.     public static void main(String[] args) {
  9.         MyThread myThread = new MyThread();
  10.         myThread.start(); // 启动线程
  11.     }
  12. }
复制代码
9.2 实现 Runnable 接口

  1. class MyRunnable implements Runnable {
  2.     @Override
  3.     public void run() {
  4.         System.out.println("线程 " + Thread.currentThread().getName() + " 运行中...");
  5.     }
  6. }
  7. public class RunnableExample {
  8.     public static void main(String[] args) {
  9.         MyRunnable myRunnable = new MyRunnable();
  10.         Thread thread = new Thread(myRunnable, "MyThread");
  11.         thread.start(); // 启动线程
  12.     }
  13. }
复制代码
9.3 实现 Callable 接口

  1. import java.util.concurrent.Callable;
  2. import java.util.concurrent.ExecutionException;
  3. import java.util.concurrent.ExecutorService;
  4. import java.util.concurrent.Executors;
  5. import java.util.concurrent.Future;
  6. class MyCallable implements Callable<Integer> {
  7.     @Override
  8.     public Integer call() throws Exception {
  9.         int sum = 0;
  10.         for (int i = 0; i < 100; i++) {
  11.             sum += i;
  12.         }
  13.         return sum;
  14.     }
  15. }
  16. public class CallableExample {
  17.     public static void main(String[] args) {
  18.         ExecutorService executorService = Executors.newFixedThreadPool(2);
  19.         Future<Integer> future = executorService.submit(new MyCallable());
  20.         try {
  21.             int result = future.get(); // 获取结果
  22.             System.out.println("计算结果: " + result);
  23.         } catch (InterruptedException | ExecutionException e) {
  24.             e.printStackTrace();
  25.         } finally {
  26.             executorService.shutdown(); // 关闭线程池
  27.         }
  28.     }
  29. }
复制代码
9.4 线程同步

  1. public class SynchronizedMethodExample {
  2.     private int count = 0;
  3.     public synchronized void increment() {
  4.         count++;
  5.     }
  6.     public static void main(String[] args) {
  7.         SynchronizedMethodExample example = new SynchronizedMethodExample();
  8.         Thread t1 = new Thread(() -> {
  9.             for (int i = 0; i < 1000; i++) {
  10.                 example.increment();
  11.             }
  12.         });
  13.         Thread t2 = new Thread(() -> {
  14.             for (int i = 0; i < 1000; i++) {
  15.                 example.increment();
  16.             }
  17.         });
  18.         t1.start();
  19.         t2.start();
  20.         try {
  21.             t1.join();
  22.             t2.join();
  23.         } catch (InterruptedException e) {
  24.             e.printStackTrace();
  25.         }
  26.         System.out.println("最终计数: " + example.count);
  27.     }
  28. }
复制代码
9.5 线程间通讯

  1. public class WaitNotifyExample {
  2.     private final Object lock = new Object();
  3.     private boolean flag = false;
  4.     public void producer() {
  5.         synchronized (lock) {
  6.             while (flag) {
  7.                 try {
  8.                     lock.wait();
  9.                 } catch (InterruptedException e) {
  10.                     e.printStackTrace();
  11.                 }
  12.             }
  13.             // 生产数据
  14.             System.out.println("生产数据");
  15.             flag = true;
  16.             lock.notify();
  17.         }
  18.     }
  19.     public void consumer() {
  20.         synchronized (lock) {
  21.             while (!flag) {
  22.                 try {
  23.                     lock.wait();
  24.                 } catch (InterruptedException e) {
  25.                     e.printStackTrace();
  26.                 }
  27.             }
  28.             // 消费数据
  29.             System.out.println("消费数据");
  30.             flag = false;
  31.             lock.notify();
  32.         }
  33.     }
  34.     public static void main(String[] args) {
  35.         WaitNotifyExample example = new WaitNotifyExample();
  36.         Thread producerThread = new Thread(() -> {
  37.             for (int i = 0; i < 5; i++) {
  38.                 example.producer();
  39.             }
  40.         });
  41.         Thread consumerThread = new Thread(() -> {
  42.             for (int i = 0; i < 5; i++) {
  43.                 example.consumer();
  44.             }
  45.         });
  46.         producerThread.start();
  47.         consumerThread.start();
  48.     }
  49. }
复制代码
10. 总结

本文深入探讨了 Java 线程的基础知识,包罗 Thread 类、Runnable 接口、Callable 接口以及线程的生命周期,并联合大厂的最佳实践和底层核心原理,帮助读者全面把握这些关键技术。公道地使用线程管理机制可以进步步调的性能和响应速率,避免线程安全问题。希望本文对你有所帮助,如果你有任何问题或建议,欢迎留言交流。

希望这篇文章能够满意你的需求,如果有任何进一步的问题或必要更多内容,请随时告诉我!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

伤心客

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表