并发编程系列-Java 并发包总结

工作中常用到一些并发编程类,这里做一些总结。

JDK 中涉及到线程的包如下:

java.lang

内含基础并发类。

Runnable

无返回结果的异步任务。

Thread

程序中的执行线程。

属性

Thread 对象中保存了一些属性能够帮助我们来辨别每一个线程,知道它的状态,调整控制其优先级等:

ID

每个线程的独特标识。

Name

线程的名称。

Priority

线程对象的优先级。优先级别在 1-10 之间,1 是最低级,10 是最高级。不建议改变它们的优先级。

Daemon

是否为守护线程。

Java 有一种特别的线程叫做守护线程。这种线程的优先级非常低,通常在程序里没有其他线程运行时才会执行它。当守护线程是程序里唯一在运行的线程时,JVM 会结束守护线程并终止程序。

根据这些特点,守护线程通常用于在同一程序里给普通线程(也叫使用者线程)提供服务。它们通常无限循环的等待服务请求或执行线程任务。它们不能做重要的任务,因为我们不知道什么时候会被分配到 CPU 时间片,并且只要没有其他线程在运行,它们可能随时被终止。JAVA中最典型的这种类型代表就是垃圾回收器 GC

只能在 start() 方法之前可以调用 setDaemon() 方法。一旦线程运行了,就不能修改守护状态。

可以使用 isDaemon() 方法来检查线程是否是守护线程。

Thread.UncaughtExceptionHandler

用于捕获和处理线程对象抛出的 Unchecked Exception 来避免程序终结。

Thread.State

线程的状态,共六种:
NEW
RUNNABLE
BLOCKED
WAITING
TIME_WAITING
TERMINATED

方法

Thread 类提供了以下几类方法

  • 线程睡眠 Thread.sleep(...)
  • 线程中断 Thread.interrupt()
  • 线程让步 Thread.yield()
  • 线程合并 Thread.join(...)
  • ……

Object 提供了一组线程协作方法:

  • 线程协作 Object.wait/notify

ThreadLocal

ThreadLocal 存放的值是线程内共享的,线程间互斥的,主要用于在线程内共享一些数据。

可以通过实现 AutoCloseable 以使用 try-with-resources 语法简化 ThreadLocal 资源清理:

try (ChannelContext ctx = new ChannelContext(channel)) {
    ...
}

实现如下:

@Slf4j
public class ChannelContext implements AutoCloseable {

    private static final ThreadLocal<Channel> CTX = new ThreadLocal<>();

    public ChannelContext(FundChannelDTO dto) {
        Channel channel = Channel.builder()
                .appId(dto.getAppId().toString())
                .build();
        CTX.set(channel);
    }

    public ChannelContext(Channel channel) {
        CTX.set(channel);
    }

    public static Channel get() {
        return CTX.get();
    }

    @Override
    public void close() {
        try {
            CTX.remove();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    @Getter
    @Builder
    static class Channel {
        private final String appId;
    }

}

ThreadGroup

java.util

TimerTask

Timer 是 JDK 中提供的一个定时器工具类,使用的时候会在主线程之外起一个单独的线程执行指定的定时任务 TimerTask,可以指定执行一次或者反复执行多次。

TimerTask 是一个实现了 Runnable 接口的抽象类,代表一个可以被 Timer 执行的任务。

TimerTask

java.util.concurrent

JDK 5 引入的 Executor Framework ,用于取代传统的并发编程。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YW7QUmEY-1612353678304)(https://qidawu.github.io/img/java/concurrent/package_concurrent.png)]

ThreadFactory

通过提供不同的 ThreadFactory 接口实现,可以改变被创建线程 Thread属性ThreadFactory 有几种创建方式:

1、完全自定义方式。缺点是需要在 newThread 方法中实现的代码较多:

ThreadFactory threadFactory = runnable -> {
    Thread thread = new Thread(runnable);
    thread.setName("...");
    return thread;
};

2、使用 Executors 工具类,这也是 Executors 工具类中提供的几种默认线程池所使用的方式。

缺点是只能使用默认属性,无法修改:

ThreadFactory threadFactory = Executors.defaultThreadFactory();

优点是实现了基本的线程名称自增,该实现如下:

/**
 * The default thread factory
 */
static class DefaultThreadFactory implements ThreadFactory {
    private static final AtomicInteger poolNumber = new AtomicInteger(1);
    private final ThreadGroup group;
    private final AtomicInteger threadNumber = new AtomicInteger(1);
    private final String namePrefix;

    DefaultThreadFactory() {
        SecurityManager s = System.getSecurityManager();
        group = (s != null) ? s.getThreadGroup() :
                              Thread.currentThread().getThreadGroup();
        namePrefix = "pool-" +
                      poolNumber.getAndIncrement() +
                     "-thread-";
    }

    public Thread newThread(Runnable r) {
        Thread t = new Thread(group, r,
                              namePrefix + threadNumber.getAndIncrement(),
                              0);
        if (t.isDaemon())
            t.setDaemon(false);
        if (t.getPriority() != Thread.NORM_PRIORITY)
            t.setPriority(Thread.NORM_PRIORITY);
        return t;
    }
}

3、通过 Guava 提供的 ThreadFactoryBuilder。优点是可以轻易自定义任何属性:

ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("wechat-notify-%d").build()

该实现如下,如果未提供自定义的 ThreadFactory,将使用 Executors 工具类提供的默认 ThreadFactory 并进行二次修改:

private static ThreadFactory build(ThreadFactoryBuilder builder) {
  final String nameFormat = builder.nameFormat;
  final Boolean daemon = builder.daemon;
  final Integer priority = builder.priority;
  final UncaughtExceptionHandler uncaughtExceptionHandler = builder.uncaughtExceptionHandler;
  final ThreadFactory backingThreadFactory = (builder.backingThreadFactory != null)
          ? builder.backingThreadFactory
          : Executors.defaultThreadFactory();
  final AtomicLong count = (nameFormat != null) ? new AtomicLong(0) : null;

  return new ThreadFactory() {
    @Override
    public Thread newThread(Runnable runnable) {
      Thread thread = backingThreadFactory.newThread(runnable);
      if (nameFormat != null) {
        thread.setName(format(nameFormat, count.getAndIncrement()));
      }
      if (daemon != null) {
        thread.setDaemon(daemon);
      }
      if (priority != null) {
        thread.setPriority(priority);
      }
      if (uncaughtExceptionHandler != null) {
        thread.setUncaughtExceptionHandler(uncaughtExceptionHandler);
      }
      return thread;
    }
  };
}

Callable

有返回结果的异步任务。Executor Framework 的一个重要优点是提供了 java.util.concurrent.Callable<V> 接口用于返回异步任务的结果。它的用法跟 Runnable 接口很相似,但它提供了两种改进:

  • 这个接口中主要的方法叫 call() ,可以返回结果。
  • 当你提交 Callable 对象到 Executor 执行者,你可以获取一个实现 Future 接口的对象,你可以用这个对象来控制和获取 Callable 对象的状态和结果。

工具类

CountDownLatch
CyclicBarrier
Phaser
CompletableFuture
Semaphore
Exchanger
Executors

线程池

参考另一篇《Java 并发编程系列(二)线程池总结》。

并发集合

详见另一个篇《Java 集合框架系列(三)并发实现总结》。

显式锁

java.util.concurrent.locks

用于实现线程安全与通信。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RoRkVjSa-1612353678306)(https://qidawu.github.io/img/java/concurrent/package_locks.png)]

原子类

java.util.concurrent.atomic

使用这些数据结构可以避免在并发程序中使用同步代码块(synchronized 或 Lock)。

Package atomic

JDK 5 新增的原子类,底层基于魔术类 Unsafe 进行 CAS 无锁操作。实现类按功能分组如下:

IntegerLongBoolean引用类型
基本类AtomicIntegerAtomicLongAtomicBoolean
引用类型AtomicReference AtomicStampedReference AtomicMarkableReference
数组类型AtomicIntegerArrayAtomicLongArrayAtomicReferenceArray
属性原子修改器AtomicIntegerFieldUpdaterAtomicLongFieldUpdaterAtomicReferenceFieldUpdater

JDK 8 新增 Striped64 累加计数器这个并发组件,64 指的是计数 64 bit 的数,即 LongDouble 类型。其实现类如下:

LongDouble
LongAdderDoubleAdder
LongAccumulatorDoubleAccumulator

性能对比参考:http://www.manongjc.com/article/105666.html

Spring 包简介

org.springframework.scheduling

Spring Framework 中并发编程相关的类主要位于 spring-context 下的 org.springframework.scheduling,例如其子包 concurrent

org.springframework.scheduling.concurrent

其中,顶层的 org.springframework.scheduling.concurrent.CustomizableThreadFactory 结构如下:

org.springframework.util.CustomizableThreadFactory

  • CustomizableThreadFactory 实现了 java.util.concurrent.ThreadFactory 线程工厂接口,源码如下:

    // Executors.defaultThreadFactory 方法提供了一个实用的简单实现,为新线程设置了上下文,详见源码
    public interface ThreadFactory {
        Thread newThread(Runnable r);
    }
    
  • CustomizableThreadFactory 继承了 org.springframework.util.CustomizableThreadCreator 类,用于创建新线程,并提供各种线程属性自定义配置(如线程名前缀、线程优先级等)。

然后重点看下最常用的 org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor 类,提供的方法列表如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N7srMU7W-1612353678312)(https://qidawu.github.io/img/java/concurrent/ThreadPoolTaskExecutor.png)]

当我们在实例化 ThreadPoolTaskExecutor 类的时候,其调用堆栈如下:

img

可见,实际上是先调用了抽象父类 ExecutorConfigurationSupportafterPropertiesSet()initialize() 方法,最后再调用 ThreadPoolTaskExecutor#initializeExecutor(...),该方法源码如下:

@Override
protected ExecutorService initializeExecutor(
        ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {

    BlockingQueue<Runnable> queue = createQueue(this.queueCapacity);

    ThreadPoolExecutor executor;
    if (this.taskDecorator != null) {
        executor = new ThreadPoolExecutor(
                this.corePoolSize, this.maxPoolSize, this.keepAliveSeconds, TimeUnit.SECONDS,
                queue, threadFactory, rejectedExecutionHandler) {
            @Override
            public void execute(Runnable command) {
                super.execute(taskDecorator.decorate(command));
            }
        };
    }
    else {
        executor = new ThreadPoolExecutor(
                this.corePoolSize, this.maxPoolSize, this.keepAliveSeconds, TimeUnit.SECONDS,
                queue, threadFactory, rejectedExecutionHandler);

    }

    if (this.allowCoreThreadTimeOut) {
        executor.allowCoreThreadTimeOut(true);
    }

    this.threadPoolExecutor = executor;
    return executor;
}

实际上就是通过构造方法实例化 java.util.concurrent.ThreadPoolExecutor 对象,并设置相应参数。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dylan、

耕码不易,白嫖可耻

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值