多线程的创建

0x00 多线程的创建

有以下4种创建线程的方法

1. 继承Thread类

1
2
3
4
5
public class MyThread extends Thread {
@Override
public void run() {
}
}

2. 实现Runnable接口

1
2
3
4
5
public class MyRunnable implements Runnable {
@Override
public void run() {
}
}

3. 实现Callable接口

1
2
3
4
5
6
public class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
return null;
}
}

4. 使用线程池

1
2
3
ExecutorService executorService = Executors.newFixedThreadPool(10);
executorService.execute(() -> {});
executorService.shutdown();

0x01 线程池基本使用

1. 线程池的创建

1
ExecutorService executorService = Executors.newFixedThreadPool(10);

2. 线程池的关闭

1
executorService.shutdown();

3. 线程池的执行

无需线程返回数据时使用execute 直接执行线程.

1
executorService.execute(() -> {});

4. 线程池的提交

当需要线程返回数据时使用submit 提交线程. 并使用Future 获取线程返回的数据.
如果这时调用executorService.shutdown()
线程池会等待全部线程执行完毕再关闭.

1
2
Future<Integer> future = executorService.submit(() -> 1);
Integer result = future.get();

0x02 几种不同的线程池

有4种不同的实现线程池, 主要区别在于线程池的容量和线程队列的实现. 除newScheduledThreadPool外使用ThreadPoolExecutor实现,newScheduledThreadPool则使用ScheduledThreadPoolExecutor实现

1. newFixedThreadPool

使用LinkedBlockingQueue 作为线程队列.

1
ExecutorService executorService = Executors.newFixedThreadPool(10);

2. newCachedThreadPool

使用SynchronousQueue作为线程队列.

1
ExecutorService executorService = Executors.newCachedThreadPool();

3. newSingleThreadExecutor

顾名思义单单线程池, 只有一个线程.

1
ExecutorService executorService = Executors.newSingleThreadExecutor();

4. newScheduledThreadPool

使用DelayedWorkQueue作为线程队列.

1
2
3
4
5
6
7
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(10);
// 指定时间后开始执行
executorService.schedule(() -> {}, 1, TimeUnit.SECONDS);
// 指定时间后开始执行, 每隔一段时间执行一次
executorService.scheduleAtFixedRate(() -> {}, 1, 1, TimeUnit.SECONDS);
// 指定时间后开始执行, 上一次任务执行成功后再隔一段时间执行一次
executorService.scheduleWithFixedDelay(() -> {}, 1, 1, TimeUnit.SECONDS);

0x03 线程池的参数

线程池的参数有:

  • corePoolSize: 线程池的核心线程数. 当线程池中的线程数小于corePoolSize时, 会创建新的线程. 当线程池中的线程数大于corePoolSize时, 会使用线程队列.
  • maximumPoolSize: 线程池的最大线程数. 当线程池中的线程数大于maximumPoolSize时, 会使用线程队列.
  • keepAliveTime: 线程池中线程的空闲时间. 当线程池中的线程空闲时间大于keepAliveTime时, 会销毁线程.
  • unit: keepAliveTime的单位.
  • workQueue: 线程队列. 当线程池中的线程数大于corePoolSize时, 会使用线程队列. 线程队列的实现有:
    • ArrayBlockingQueue: 有界队列, 使用数组实现.
    • LinkedBlockingQueue: 无界队列, 使用链表实现.
    • SynchronousQueue: 同步队列, 没有容量, 每个插入操作必须等待一个移除操作.
    • PriorityBlockingQueue: 优先队列, 使用堆实现.
  • threadFactory: 线程工厂. 用于创建线程. 默认使用Executors.defaultThreadFactory()创建.
  • handler: 拒绝策略. 当线程池中的线程数大于maximumPoolSize时, 会使用拒绝策略. 默认使用AbortPolicy()拒绝策略.
    • AbortPolicy: 拒绝策略, 当线程池中的线程数大于maximumPoolSize时, 会抛出RejectedExecutionException异常.
    • CallerRunsPolicy: 拒绝策略, 当线程池中的线程数大于maximumPoolSize时, 会使用调用者所在的线程来执行任务.
    • DiscardPolicy: 拒绝策略, 当线程池中的线程数大于maximumPoolSize时, 会丢弃任务.
    • DiscardOldestPolicy: 拒绝策略, 当线程池中的线程数大于maximumPoolSize时, 会丢弃队列中最老的任务.
      1
      2
      3
      4
      5
      6
      7
      8
      9
      ExecutorService executorService = new ThreadPoolExecutor(
      corePoolSize,
      maximumPoolSize,
      keepAliveTime,
      unit,
      workQueue,
      threadFactory,
      handler
      );

0x04 几种Queue

SynchronousQueue

特性:

  • SynchronousQueue 是一种特殊的无界队列,它实际上并不存储任何元素。
  • 当一个线程试图通过 put 方法插入一个元素时,该操作会一直阻塞,直到另一个线程通过 take 方法取走该元素。
  • 同样地,当一个线程尝试从 SynchronousQueue 中获取一个元素时,如果没有其他线程放入元素,该操作也会被阻塞。

用途:

  • 主要用于线程间的通信,特别是作为生产者消费者模式中的一种传递机制。
  • 可以用于实现线程池中的工作窃取模型,在这种模型中,空闲的线程可以从其他繁忙的线程那里窃取任务来执行。

LinkedBlockingQueue

特性:

  • LinkedBlockingQueue 是一个基于链表结构的阻塞队列,它提供了容量可配置的能力。
  • 默认情况下,它的容量是 Integer.MAX_VALUE,意味着它可以无限扩展,但在实际应用中,通常会显式指定一个容量限制。
  • 如果队列已满,put 操作将阻塞,直到队列中有可用空间。
  • 如果队列为空,take 操作将阻塞,直到队列中有新的元素。

用途:

  • 适用于需要缓冲处理的数据流场景。
  • 适合于生产者消费者模式,其中生产者和消费者的速率可能不一致。
  • 在实现线程池时,LinkedBlockingQueue 是一个常见的选择,因为它可以根据实际情况动态调整队列大小。

ArrayBlockingQueue

特性:

  • ArrayBlockingQueue 是一个由数组支持的有界阻塞队列。
  • 它提供了一个固定大小的缓冲区,用于存储队列中的元素。
  • 当队列满了时,put 操作会阻塞,直到队列中有可用空间。
  • 当队列为空时,take 操作会阻塞,直到队列中有新的元素。

用途:

  • 适用于需要对队列的大小进行限制的场景。
  • 适合于生产者消费者模式,其中生产者和消费者的速率可能不一致,但队列的大小是有限的。

PriorityBlockingQueue

特性:

  • PriorityBlockingQueue 是一个无界的优先级阻塞队列。
  • 它使用优先级堆(类似于最小堆或最大堆)来维护队列中的元素。
  • 元素会被按照自然排序顺序或通过比较器确定的顺序进行排序。
  • take 方法总是返回并移除优先级最高的元素。
  • offer 方法可以在不阻塞的情况下添加元素,但如果队列已满,put 操作会阻塞,直到队列中有可用空间。

用途:

  • 适用于需要根据优先级来调度任务的场景。
  • 适合于实现优先级队列,比如在调度算法中按照任务的优先级来决定执行顺序。

文章标题:多线程的创建

本文作者:zhu8fei

发布时间:2024-08-14, 09:31:21

最后更新:2024-08-15, 09:37:02

原始链接:http://www.zhu8fei.com/2024/08/14/thread-create.html

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 zhu8fei@163.com

目录
×

喜欢就点赞,疼爱就打赏