Java 多线程

Java 多线程

一、线程的基本概念

  1. 线程是什么:

    • 线程是程序执行的最小单位,它可以独立执行一段代码。
    • 一个进程可以包含多个线程,它们共享进程的内存空间和资源。
  2. 线程的状态:

    • 新建(New):线程刚刚被创建,还没有开始执行。
    • 就绪(Runnable):线程已经准备好执行,等待 CPU 分配时间片。
    • 运行(Running):线程正在执行。
    • 阻塞(Blocked):线程因为等待某个条件而暂停执行,如等待输入、等待锁等。
    • 死亡(Dead):线程执行完毕或因为异常而终止。

二、创建线程的方式

  1. 继承Thread类:

    • 创建一个类继承自Thread类,并重写run方法,在run方法中编写线程要执行的代码。
    • 示例:
      class MyThread extends Thread {
          @Override
          public void run() {
              System.out.println("This is a custom thread.");
          }
      }
      
      public class ThreadCreationExample {
          public static void main(String[] args) {
              MyThread thread = new MyThread();
              thread.start();
          }
      }
      
  2. 实现Runnable接口:

    • 创建一个类实现Runnable接口,并实现run方法。
    • 然后创建一个Thread对象,将实现了Runnable接口的对象作为参数传递给Thread构造函数,并调用start方法启动线程。
    • 示例:
      class MyRunnable implements Runnable {
          @Override
          public void run() {
              System.out.println("This is a thread implemented using Runnable.");
          }
      }
      
      public class ThreadCreationRunnableExample {
          public static void main(String[] args) {
              MyRunnable runnable = new MyRunnable();
              Thread thread = new Thread(runnable);
              thread.start();
          }
      }
      

三、线程的优先级

  1. 设置优先级:

    • Java 线程的优先级可以通过setPriority方法来设置,范围从 1(最低优先级)到 10(最高优先级)。默认优先级为 5。
    • 示例:
      class MyHighPriorityThread extends Thread {
          @Override
          public void run() {
              System.out.println("High priority thread is running.");
          }
      }
      
      class MyLowPriorityThread extends Thread {
          @Override
          public void run() {
              System.out.println("Low priority thread is running.");
          }
      }
      
      public class ThreadPriorityExample {
          public static void main(String[] args) {
              MyHighPriorityThread highPriorityThread = new MyHighPriorityThread();
              highPriorityThread.setPriority(Thread.MAX_PRIORITY);
      
              MyLowPriorityThread lowPriorityThread = new MyLowPriorityThread();
              lowPriorityThread.setPriority(Thread.MIN_PRIORITY);
      
              highPriorityThread.start();
              lowPriorityThread.start();
          }
      }
      
  2. 优先级的影响:

    • 优先级高的线程并不一定总是先执行,只是在竞争资源时更有可能被调度执行。实际的执行顺序还取决于操作系统的调度算法。

四、线程同步

  1. 同步方法:

    • 使用synchronized关键字修饰方法,可以确保在同一时间只有一个线程能够访问该方法。
    • 示例:
      class Counter {
          private int count = 0;
      
          public synchronized void increment() {
              count++;
          }
      
          public int getCount() {
              return count;
          }
      }
      
      class MyThreadForCounter extends Thread {
          private Counter counter;
      
          public MyThreadForCounter(Counter counter) {
              this.counter = counter;
          }
      
          @Override
          public void run() {
              for (int i = 0; i < 1000; i++) {
                  counter.increment();
              }
          }
      }
      
      public class SynchronizedMethodExample {
          public static void main(String[] args) {
              Counter counter = new Counter();
              MyThreadForCounter thread1 = new MyThreadForCounter(counter);
              MyThreadForCounter thread2 = new MyThreadForCounter(counter);
      
              thread1.start();
              thread2.start();
      
              try {
                  thread1.join();
                  thread2.join();
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
      
              System.out.println("Final count: " + counter.getCount());
          }
      }
      
  2. 同步块:

    • 使用synchronized关键字修饰代码块,可以指定一个对象作为锁,确保在同一时间只有一个线程能够访问该代码块。
    • 示例:
      class CounterWithSyncBlock {
          private int count = 0;
          private Object lock = new Object();
      
          public void increment() {
              synchronized (lock) {
                  count++;
              }
          }
      
          public int getCount() {
              return count;
          }
      }
      
      class MyThreadForSyncBlock extends Thread {
          private CounterWithSyncBlock counter;
      
          public MyThreadForSyncBlock(CounterWithSyncBlock counter) {
              this.counter = counter;
          }
      
          @Override
          public void run() {
              for (int i = 0; i < 1000; i++) {
                  counter.increment();
              }
          }
      }
      
      public class SynchronizedBlockExample {
          public static void main(String[] args) {
              CounterWithSyncBlock counter = new CounterWithSyncBlock();
              MyThreadForSyncBlock thread1 = new MyThreadForSyncBlock(counter);
              MyThreadForSyncBlock thread2 = new MyThreadForSyncBlock(counter);
      
              thread1.start();
              thread2.start();
      
              try {
                  thread1.join();
                  thread2.join();
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
      
              System.out.println("Final count with sync block: " + counter.getCount());
          }
      }
      

五、线程间通信

  1. wait和notify方法:
    • wait方法使当前线程等待,直到另一个线程调用notify或notifyAll方法唤醒它。
    • notify方法唤醒一个等待的线程,notifyAll方法唤醒所有等待的线程。
    • 示例:
      class SharedResource {
          private int value = 0;
          private boolean available = false;
      
          public synchronized int getValue() {
              while (!available) {
                  try {
                      wait();
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }
              available = false;
              notifyAll();
              return value;
          }
      
          public synchronized void setValue(int value) {
              while (available) {
                  try {
                      wait();
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }
              this.value = value;
              available = true;
              notifyAll();
          }
      }
      
      class Producer extends Thread {
          private SharedResource resource;
      
          public Producer(SharedResource resource) {
              this.resource = resource;
          }
      
          @Override
          public void run() {
              for (int i = 1; i <= 10; i++) {
                  resource.setValue(i);
                  System.out.println("Produced: " + i);
              }
          }
      }
      
      class Consumer extends Thread {
          private SharedResource resource;
      
          public Consumer(SharedResource resource) {
              this.resource = resource;
          }
      
          @Override
          public void run() {
              for (int i = 1; i <= 10; i++) {
                  int value = resource.getValue();
                  System.out.println("Consumed: " + value);
              }
          }
      }
      
      public class ThreadCommunicationExample {
          public static void main(String[] args) {
              SharedResource resource = new SharedResource();
              Producer producer = new Producer(resource);
              Consumer consumer = new Consumer(resource);
      
              producer.start();
              consumer.start();
          }
      }
      

六、线程安全的集合类

  1. ConcurrentHashMap:

    • 是一个线程安全的哈希表,支持高并发的读写操作。
    • 示例:
      import java.util.concurrent.ConcurrentHashMap;
      
      public class ConcurrentHashMapExample {
          public static void main(String[] args) {
              ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
              map.put("apple", 5);
              map.put("banana", 3);
      
              Integer value = map.get("apple");
              System.out.println("Value for 'apple': " + value);
          }
      }
      
  2. CopyOnWriteArrayList:

    • 是一个线程安全的列表,在进行写操作时会复制一份原列表,避免了在迭代过程中的并发修改异常。
    • 示例:
      import java.util.concurrent.CopyOnWriteArrayList;
      
      public class CopyOnWriteArrayListExample {
          public static void main(String[] args) {
              CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
              list.add("apple");
              list.add("banana");
      
              for (String item : list) {
                  System.out.println(item);
              }
          }
      }
      

七、线程池

一、Java 线程池简介

线程池是一种多线程处理形式,它可以管理一组工作线程,在需要执行任务时从线程池中获取线程,任务执行完毕后将线程归还到线程池中,以实现线程的复用,减少线程创建和销毁的开销。

二、Java 线程池的主要组成部分

  1. ThreadPoolExecutor:这是 Java 线程池的核心实现类,它接受一系列参数来配置线程池的行为。

    • corePoolSize:核心线程数,即使线程处于空闲状态也会保留在池中。
    • maximumPoolSize:最大线程数,当任务队列已满且有新任务提交时,线程池会创建新线程直到达到这个数量。
    • keepAliveTime:当线程数大于核心线程数时,多余的空闲线程在这个时间后会被终止。
    • unit:keepAliveTime的时间单位。
    • workQueue:用于存储等待执行的任务的队列。
    • threadFactory:用于创建线程的工厂。
    • rejectedExecutionHandler:当任务提交时线程池无法处理时的拒绝策略。
  2. 任务队列(BlockingQueue):用于存储等待执行的任务,常见的有LinkedBlockingQueue、ArrayBlockingQueue等。

  3. 拒绝策略:当线程池无法处理新任务时采取的策略,常见的有以下几种:

    • AbortPolicy:直接抛出RejectedExecutionException异常。
    • CallerRunsPolicy:在调用者线程中执行任务。
    • DiscardPolicy:默默丢弃无法处理的任务。
    • DiscardOldestPolicy:丢弃队列中最旧的任务,并尝试重新提交新任务。

三、Java 线程池的使用方法

  1. 创建线程池:

    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ThreadPoolExecutor;
    
    public class ThreadPoolExample {
        public static void main(String[] args) {
            // 创建一个固定大小的线程池,包含 5 个线程
            ExecutorService executorService = Executors.newFixedThreadPool(5);
            ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executorService;
    
            for (int i = 0; i < 10; i++) {
                Runnable task = () -> {
                    System.out.println("Task " + Thread.currentThread().getName() + " is running.");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                };
                executorService.execute(task);
            }
    
            // 查看线程池的一些信息
            System.out.println("Core pool size: " + threadPoolExecutor.getCorePoolSize());
            System.out.println("Maximum pool size: " + threadPoolExecutor.getMaximumPoolSize());
            System.out.println("Number of threads: " + threadPoolExecutor.getPoolSize());
            System.out.println("Number of active threads: " + threadPoolExecutor.getActiveCount());
    
            executorService.shutdown();
        }
    }
    
  2. 自定义线程池:

    import java.util.concurrent.BlockingQueue;
    import java.util.concurrent.LinkedBlockingQueue;
    import java.util.concurrent.ThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;
    
    public class CustomThreadPoolExample {
        public static void main(String[] args) {
            // 创建自定义线程池
            BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(10);
            ThreadPoolExecutor executor = new ThreadPoolExecutor(
                    3, 5, 10, TimeUnit.SECONDS, queue);
    
            for (int i = 0; i < 15; i++) {
                Runnable task = () -> {
                    System.out.println("Task " + Thread.currentThread().getName() + " is running.");
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                };
                executor.execute(task);
            }
    
            executor.shutdown();
        }
    }
    

四、结合 Spring Boot 使用线程池

  1. 配置线程池:

    • 在 Spring Boot 中,可以通过配置类来创建和配置线程池。
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
    
    import java.util.concurrent.Executor;
    
    @Configuration
    public class ThreadPoolConfig {
        @Bean
        public Executor taskExecutor() {
            ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
            executor.setCorePoolSize(5);
            executor.setMaxPoolSize(10);
            executor.setQueueCapacity(20);
            executor.setThreadNamePrefix("my-thread-");
            executor.initialize();
            return executor;
        }
    }
    
  2. 使用线程池:

    • 在需要执行异步任务的地方注入线程池,并使用它来执行任务。
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.scheduling.annotation.Async;
    import org.springframework.stereotype.Service;
    
    @Service
    public class MyService {
        @Autowired
        private java.util.concurrent.Executor taskExecutor;
    
        public void doAsyncTask() {
            taskExecutor.execute(() -> {
                // 异步任务的代码
                System.out.println("Async task is running.");
            });
        }
    }
    
posted @ 2026-07-29 09:45  渔樵江渚  阅读(5)  评论(0)    收藏  举报