用示例代码理解java多线程编程

package threads;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**

  • Java多线程编程演示类

  • 本类演示了Java多线程编程的核心概念和常用技术,包括:

    1. 线程创建:继承Thread类 vs 实现Runnable接口
    1. 线程同步:synchronized关键字
    1. 线程通信:wait/notify机制
    1. 线程池:Executor框架
    1. 并发工具:Lock、Atomic类等
  • 重要概念:

    • 线程安全:多线程环境下数据的一致性
    • 死锁:线程相互等待资源
    • 线程生命周期:新建、就绪、运行、阻塞、死亡
      */
      public class ThreadDemo {

    /**

    • 演示多线程编程的入口方法

    • 该方法按顺序调用各个演示方法,展示Java多线程的核心功能
      */
      public static void demo() {
      // 打印演示开始信息
      System.out.println(“\n=== 多线程编程演示开始 ===”);

      // 1. 线程创建演示 - 演示不同的线程创建方式
      demonstrateThreadCreation();

      // 2. 线程同步演示 - 展示线程安全问题及解决方案
      demonstrateThreadSynchronization();

      // 3. 线程通信演示 - 演示基于wait/notify的线程间通信
      demonstrateThreadCommunication();

      // 4. 线程池演示 - 展示Executor框架的使用
      demonstrateThreadPool();

      // 5. 并发工具演示 - 展示高级并发工具的使用
      demonstrateConcurrencyTools();

      // 打印演示结束信息
      System.out.println(“=== 多线程编程演示结束 ===\n”);
      }

    /**

    • 演示线程创建的三种方式

      1. 继承Thread类
      1. 实现Runnable接口
      1. 使用Lambda表达式(Java 8+)
    • 每种方式都创建并启动线程,并等待其执行完成
      */
      private static void demonstrateThreadCreation() {
      // 打印当前演示的标题
      System.out.println(“\n— 线程创建演示 —”);

      // 方法1:继承Thread类
      // 创建两个自定义线程对象
      MyThread thread1 = new MyThread(“线程A”);
      MyThread thread2 = new MyThread(“线程B”);

      // 启动线程 - 调用start()方法而不是直接调用run()
      thread1.start();
      thread2.start();

      // 等待线程执行完成 - 确保当前线程等待thread1和thread2执行完毕
      try {
      thread1.join();
      thread2.join();
      } catch (InterruptedException e) {
      // 打印异常堆栈信息
      e.printStackTrace();
      }

      // 方法2:实现Runnable接口
      System.out.println(“\n— 实现Runnable接口 —”);
      // 创建线程对象,传入Runnable实现类
      Thread runnableThread1 = new Thread(new MyRunnable(“Runnable线程1”));
      Thread runnableThread2 = new Thread(new MyRunnable(“Runnable线程2”));

      // 启动线程
      runnableThread1.start();
      runnableThread2.start();

      // 等待线程执行完成
      try {
      runnableThread1.join();
      runnableThread2.join();
      } catch (InterruptedException e) {
      e.printStackTrace();
      }

      // 方法3:使用Lambda表达式(Java 8+)
      System.out.println(“\n— Lambda表达式创建线程 —”);
      // 使用Lambda表达式简化Runnable接口的实现
      Thread lambdaThread = new Thread(() -> {
      // 循环执行3次
      for (int i = 1; i <= 3; i++) {
      // 获取当前线程名称并打印计数信息
      System.out.println(Thread.currentThread().getName() + " - Lambda计数: " + i);
      try {
      // 线程休眠100毫秒
      Thread.sleep(100);
      } catch (InterruptedException e) {
      e.printStackTrace();
      }
      }
      }, “Lambda线程”);

      // 启动线程
      lambdaThread.start();
      // 等待线程执行完成
      try {
      lambdaThread.join();
      } catch (InterruptedException e) {
      e.printStackTrace();
      }
      }

    /**

    • 演示线程同步机制

    • 对比普通计数器(非线程安全)和同步计数器(线程安全)

    • 通过创建多个线程同时访问共享资源,展示线程安全问题及其解决方案
      */
      private static void demonstrateThreadSynchronization() {
      System.out.println(“\n— 线程同步演示 —”);

      // 共享资源 - 创建非线程安全的计数器实例
      Counter counter = new Counter();

      // 创建5个线程同时操作共享资源
      Thread[] threads = new Thread[5];
      for (int i = 0; i < threads.length; i++) {
      // 每个线程执行1000次递增操作
      threads[i] = new Thread(() -> {
      for (int j = 0; j < 1000; j++) {
      counter.increment();
      }
      }, “线程-” + i);
      }

      // 启动所有线程
      for (Thread thread : threads) {
      thread.start();
      }

      // 等待所有线程完成
      for (Thread thread : threads) {
      try {
      thread.join();
      } catch (InterruptedException e) {
      e.printStackTrace();
      }
      }

      // 打印最终计数,由于线程安全问题,结果可能小于5000
      System.out.println("最终计数(应该有线程安全问题): " + counter.getCount());

      // 使用同步的计数器 - 创建线程安全的计数器实例
      SynchronizedCounter syncCounter = new SynchronizedCounter();

      // 创建5个线程同时操作同步计数器
      Thread[] syncThreads = new Thread[5];
      for (int i = 0; i < syncThreads.length; i++) {
      syncThreads[i] = new Thread(() -> {
      for (int j = 0; j < 1000; j++) {
      syncCounter.increment();
      }
      }, “同步线程-” + i);
      }

      // 启动所有线程
      for (Thread thread : syncThreads) {
      thread.start();
      }

      // 等待所有线程完成
      for (Thread thread : syncThreads) {
      try {
      thread.join();
      } catch (InterruptedException e) {
      e.printStackTrace();
      }
      }

      // 打印同步计数器的最终计数,由于线程安全,结果应为5000
      System.out.println("同步计数器最终计数: " + syncCounter.getCount());
      }

    /**

    • 演示线程通信机制

    • 使用生产者-消费者模型,基于wait/notify机制实现线程间通信

    • 生产者线程生产消息,消费者线程消费消息,通过同步块确保线程安全
      */
      private static void demonstrateThreadCommunication() {
      System.out.println(“\n— 线程通信演示 —”);

      // 生产者-消费者模型 - 创建容量为3的消息队列
      MessageQueue queue = new MessageQueue(3);

      // 生产者线程 - 生产5条消息
      Thread producer = new Thread(() -> {
      for (int i = 1; i <= 5; i++) {
      String message = “消息-” + i;
      // 生产消息,当队列满时会阻塞等待
      queue.produce(message);
      System.out.println("生产: " + message);
      try {
      // 每生产一条消息后休眠500毫秒
      Thread.sleep(500);
      } catch (InterruptedException e) {
      e.printStackTrace();
      }
      }
      }, “生产者”);

      // 消费者线程 - 消费5条消息
      Thread consumer = new Thread(() -> {
      for (int i = 1; i <= 5; i++) {
      // 消费消息,当队列空时会阻塞等待
      String message = queue.consume();
      System.out.println("消费: " + message);
      try {
      // 每消费一条消息后休眠800毫秒(消费速度慢于生产速度)
      Thread.sleep(800);
      } catch (InterruptedException e) {
      e.printStackTrace();
      }
      }
      }, “消费者”);

      // 启动生产者和消费者线程
      producer.start();
      consumer.start();

      // 等待生产者和消费者线程完成
      try {
      producer.join();
      consumer.join();
      } catch (InterruptedException e) {
      e.printStackTrace();
      }
      }

    /**

    • 演示线程池的使用

    • 创建固定大小的线程池,提交多个任务并等待执行完成

    • 展示了Executor框架的基本用法和线程池的优势
      */
      private static void demonstrateThreadPool() {
      System.out.println(“\n— 线程池演示 —”);

      // 创建固定大小的线程池 - 核心线程数为3
      ExecutorService executor = Executors.newFixedThreadPool(3);

      // 提交5个任务到线程池
      for (int i = 1; i <= 5; i++) {
      // 使用final变量保存任务ID,以便在Lambda表达式中使用
      final int taskId = i;
      executor.submit(() -> {
      System.out.println(Thread.currentThread().getName() + " 执行任务 " + taskId);
      try {
      // 模拟任务执行耗时1秒
      Thread.sleep(1000);
      } catch (InterruptedException e) {
      e.printStackTrace();
      }
      System.out.println(Thread.currentThread().getName() + " 完成任务 " + taskId);
      });
      }

      // 关闭线程池 - 不再接受新任务,但会等待已提交任务完成
      executor.shutdown();

      try {
      // 等待所有任务完成,设置超时时间为10秒
      if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
      // 超时后强制关闭线程池
      executor.shutdownNow();
      }
      } catch (InterruptedException e) {
      // 捕获中断异常,强制关闭线程池
      executor.shutdownNow();
      }

      // 打印线程池任务完成信息
      System.out.println(“线程池任务全部完成”);
      }

    /**

    • 演示并发工具的使用

      1. 使用AtomicInteger进行无锁编程
      1. 使用ReentrantLock进行显式锁控制
    • 展示了Java并发包提供的高级并发工具
      */
      private static void demonstrateConcurrencyTools() {
      System.out.println(“\n— 并发工具演示 —”);

      // 使用Atomic类(无锁编程) - 创建原子计数器实例
      AtomicCounter atomicCounter = new AtomicCounter();

      // 创建5个线程同时操作原子计数器
      Thread[] atomicThreads = new Thread[5];
      for (int i = 0; i < atomicThreads.length; i++) {
      atomicThreads[i] = new Thread(() -> {
      for (int j = 0; j < 1000; j++) {
      atomicCounter.increment();
      }
      }, “原子线程-” + i);
      }

      // 启动所有线程
      for (Thread thread : atomicThreads) {
      thread.start();
      }

      // 等待所有线程完成
      for (Thread thread : atomicThreads) {
      try {
      thread.join();
      } catch (InterruptedException e) {
      e.printStackTrace();
      }
      }

      // 打印原子计数器的最终计数,结果应为5000
      System.out.println("原子计数器最终计数: " + atomicCounter.getCount());

      // 使用Lock接口 - 演示显式锁的使用
      System.out.println(“\n— Lock接口演示 —”);
      LockCounter lockCounter = new LockCounter();

      // 创建2个线程同时操作Lock计数器
      Thread lockThread1 = new Thread(() -> {
      for (int i = 0; i < 1000; i++) {
      lockCounter.increment();
      }
      }, “Lock线程1”);

      Thread lockThread2 = new Thread(() -> {
      for (int i = 0; i < 1000; i++) {
      lockCounter.increment();
      }
      }, “Lock线程2”);

      // 启动线程
      lockThread1.start();
      lockThread2.start();

      // 等待线程完成
      try {
      lockThread1.join();
      lockThread2.join();
      } catch (InterruptedException e) {
      e.printStackTrace();
      }

      // 打印Lock计数器的最终计数,结果应为2000
      System.out.println("Lock计数器最终计数: " + lockCounter.getCount());
      }
      }

/**

  • 自定义线程类 - 通过继承Thread类创建线程

  • 用于演示线程创建的第一种方式:继承Thread类并重写run方法
    */
    class MyThread extends Thread {
    // 线程名称字段
    private String threadName;

    /**

    • 构造函数,设置线程名称
    • @param name 线程名称
      */
      public MyThread(String name) {
      this.threadName = name;
      }

    /**

    • 线程执行的核心方法,重写父类Thread的run方法
    • 执行循环打印计数信息,并在每次循环后休眠100毫秒
      */
      @Override
      public void run() {
      // 循环执行3次
      for (int i = 1; i <= 3; i++) {
      // 打印线程名称和当前计数值
      System.out.println(threadName + " 运行中… 计数: " + i);
      try {
      // 线程休眠100毫秒
      Thread.sleep(100);
      } catch (InterruptedException e) {
      // 捕获中断异常并打印信息
      System.out.println(threadName + " 被中断");
      }
      }
      // 打印线程执行完成信息
      System.out.println(threadName + " 执行完成");
      }
      }

/**

  • 自定义Runnable实现类

  • 用于演示线程创建的第二种方式:实现Runnable接口
    */
    class MyRunnable implements Runnable {
    // 任务名称字段
    private String taskName;

    /**

    • 构造函数,设置任务名称
    • @param name 任务名称
      */
      public MyRunnable(String name) {
      this.taskName = name;
      }

    /**

    • 任务执行的核心方法,实现Runnable接口的run方法
    • 执行循环打印步骤信息,并在每次循环后休眠150毫秒
      */
      @Override
      public void run() {
      // 循环执行3次
      for (int i = 1; i <= 3; i++) {
      // 打印任务名称和当前步骤
      System.out.println(taskName + " 执行中… 步骤: " + i);
      try {
      // 线程休眠150毫秒
      Thread.sleep(150);
      } catch (InterruptedException e) {
      // 捕获中断异常并打印信息
      System.out.println(taskName + " 被中断");
      }
      }
      // 打印任务执行完成信息
      System.out.println(taskName + " 执行完成");
      }
      }

/**

  • 普通计数器(存在线程安全问题)

  • 用于演示非线程安全的计数器在多线程环境下的问题
    */
    class Counter {
    // 计数字段
    private int count = 0;

    /**

    • 计数器递增方法
    • 非原子操作,在多线程环境下可能导致计数不准确
    • 非线程安全
      */
      public void increment() {
      // 非原子操作,包含读取、修改、写入三个步骤
      count++; // 非原子操作,存在线程安全问题
      }

    /**

    • 获取当前计数值
    • @return 当前计数值
      */
      public int getCount() {
      // 返回当前计数值
      return count;
      }
      }

/**

  • 同步计数器(线程安全)

  • 使用synchronized关键字保证线程安全
    */
    class SynchronizedCounter {
    // 计数字段
    private int count = 0;

    /**

    • 同步递增方法
    • 使用synchronized关键字确保多线程环境下的原子性
    • 线程安全
      */
      public synchronized void increment() {
      // 使用synchronized关键字保证原子操作
      count++;
      }

    /**

    • 同步获取计数值方法
    • 使用synchronized关键字确保多线程环境下的可见性
    • @return 当前计数值
      */
      public synchronized int getCount() {
      // 使用synchronized关键字保证可见性
      return count;
      }
      }

/**

  • 消息队列(生产者-消费者模型)

  • 实现了基于wait/notify机制的线程通信
    */
    class MessageQueue {
    private final String[] messages; // 存储消息的数组
    private int count = 0; // 当前消息数量
    private int putIndex = 0; // 下一个消息放入的索引
    private int takeIndex = 0; // 下一个消息取出的索引

    /**

    • 构造函数,设置队列容量
    • @param capacity 队列最大容量
      */
      public MessageQueue(int capacity) {
      // 初始化消息存储数组
      messages = new String[capacity];
      }

    /**

    • 生产消息方法

    • 当队列满时等待,生产消息后通知消费者

    • @param message 要生产的消息
      */
      public synchronized void produce(String message) {
      // 使用while循环检查条件,防止虚假唤醒
      while (count == messages.length) {
      try {
      // 队列满,等待消费者消费
      wait();
      } catch (InterruptedException e) {
      // 打印异常堆栈信息
      e.printStackTrace();
      }
      }

      // 将消息放入队列
      messages[putIndex] = message;
      // 更新下一个消息放入的索引,循环使用数组空间
      putIndex = (putIndex + 1) % messages.length; // 循环使用数组空间
      // 增加消息计数
      count++;
      // 通知所有等待的消费者线程
      notifyAll(); // 通知消费者可以消费了
      }

    /**

    • 消费消息方法

    • 当队列空时等待,消费消息后通知生产者

    • @return 消费的消息
      */
      public synchronized String consume() {
      // 使用while循环检查条件,防止虚假唤醒
      while (count == 0) {
      try {
      // 队列空,等待生产者生产
      wait(); // 队列空,等待生产者生产
      } catch (InterruptedException e) {
      // 打印异常堆栈信息
      e.printStackTrace();
      }
      }

      // 从队列中取出消息
      String message = messages[takeIndex];
      // 更新下一个消息取出的索引,循环使用数组空间
      takeIndex = (takeIndex + 1) % messages.length; // 循环使用数组空间
      // 减少消息计数
      count–;
      // 通知所有等待的生产者线程
      notifyAll(); // 通知生产者可以生产了
      // 返回消费的消息
      return message;
      }
      }

/**

  • 原子计数器(使用AtomicInteger)

  • 基于CAS(Compare-And-Swap)操作实现线程安全的计数
    */
    class AtomicCounter {
    // 使用AtomicInteger实现原子计数
    private AtomicInteger count = new AtomicInteger(0);

    /**

    • 原子递增方法
    • 使用AtomicInteger的原子操作确保线程安全
    • 无锁实现,性能优于synchronized
      */
      public void increment() {
      // 原子递增操作,基于CAS机制实现
      count.incrementAndGet(); // 原子操作
      }

    /**

    • 获取当前计数值
    • @return 当前计数值
      */
      public int getCount() {
      // 获取当前计数值
      return count.get();
      }
      }

/**

  • 使用Lock接口的计数器

  • 演示显式锁的使用方式
    */
    class LockCounter {
    // 计数字段
    private int count = 0;
    // 创建可重入锁实例
    private Lock lock = new ReentrantLock(); // 可重入锁

    /**

    • 使用显式锁的递增方法
    • 获取锁后执行递增操作,在finally块中确保锁的释放
      */
      public void increment() {
      // 获取锁
      lock.lock(); // 获取锁
      try {
      // 执行递增操作
      count++;
      } finally {
      // 确保锁的释放,防止死锁
      lock.unlock(); // 释放锁(确保在finally块中释放)
      }
      }

    /**

    • 使用显式锁获取计数值
    • 获取锁后读取计数值,在finally块中确保锁的释放
    • @return 当前计数值
      */
      public int getCount() {
      // 获取锁
      lock.lock();
      try {
      // 返回当前计数值
      return count;
      } finally {
      // 确保锁的释放
      lock.unlock();
      }
      }
      }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值