简介
现在我们很多时候都会用到线程池,有时候我们在一个项目会用到多个或者多种线程池,对线程池管理也是非常重要的。
下面是摘抄自java nacos的线程池管理代码。
类和对象属性
首先看对象,有
private Map<String, Map<String, Set<ExecutorService>>> resourcesManager;
private Map<String, Object> lockers = new ConcurrentHashMap<>(8);
private static final ThreadPoolManager INSTANCE = new ThreadPoolManager();
private static final AtomicBoolean CLOSED = new AtomicBoolean(false);
其中resourcesManager是主要保存线程池的map对象,其中外层map的key和内层map的key主要是为了区分资源组。看自己情况加层或者减层。
lockers保存synchronized 的对象,因为resourcesManager中的对象可能为null,所以单独保存一个来做锁。lockers的value就是一个new Object();
INSTANCE 单例。
CLOSED 状态。
创建
将线程池对象保存到resourcesManager中
销毁
将线程池的对象调用ThreadUtils.shutdownThreadPool(executor);
当程序退出
需要将所有线程池退出。
看代码
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.common.executor;
import com.alibaba.nacos.common.JustForTest;
import com.alibaba.nacos.common.utils.ThreadUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* // TODO Access Metric.
*
* <p>For unified management of thread pool resources, the consumer can simply call the register method to {@link
* ThreadPoolManager#register(String, String, ExecutorService)} the thread pool that needs to be included in the life
* cycle management of the resource
*
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
*/
public final class ThreadPoolManager {
private static final Logger LOGGER = LoggerFactory.getLogger(ThreadPoolManager.class);
private Map<String, Map<String, Set<ExecutorService>>> resourcesManager;
private Map<String, Object> lockers = new ConcurrentHashMap<>(8);
private static final ThreadPoolManager INSTANCE = new ThreadPoolManager();
private static final AtomicBoolean CLOSED = new AtomicBoolean(false);
static {
INSTANCE.init();
ThreadUtils.addShutdownHook(new Thread(() -> {
LOGGER.warn("[ThreadPoolManager] Start destroying ThreadPool");
shutdown();
LOGGER.warn("[ThreadPoolManager] Destruction of the end");
}));
}
public static ThreadPoolManager getInstance() {
return INSTANCE;
}
private ThreadPoolManager() {
}
private void init() {
resourcesManager = new ConcurrentHashMap<>(8);
}
/**
* Register the thread pool resources with the resource manager.
*
* @param namespace namespace name
* @param group group name
* @param executor {@link ExecutorService}
*/
public void register(String namespace, String group, ExecutorService executor) {
if (!resourcesManager.containsKey(namespace)) {
lockers.putIfAbsent(namespace, new Object());
}
final Object monitor = lockers.get(namespace);
synchronized (monitor) {
Map<String, Set<ExecutorService>> map = resourcesManager.get(namespace);
if (map == null) {
map = new HashMap<>(8);
map.computeIfAbsent(group, key -> new HashSet<>()).add(executor);
resourcesManager.put(namespace, map);
return;
}
map.computeIfAbsent(group, key -> new HashSet<>()).add(executor);
}
}
/**
* Cancel the uniform lifecycle management for all threads under this resource.
*
* @param namespace namespace name
* @param group group name
*/
public void deregister(String namespace, String group) {
if (resourcesManager.containsKey(namespace)) {
final Object monitor = lockers.get(namespace);
synchronized (monitor) {
resourcesManager.get(namespace).remove(group);
}
}
}
/**
* Undoing the uniform lifecycle management of {@link ExecutorService} under this resource.
*
* @param namespace namespace name
* @param group group name
* @param executor {@link ExecutorService}
*/
public void deregister(String namespace, String group, ExecutorService executor) {
if (resourcesManager.containsKey(namespace)) {
final Object monitor = lockers.get(namespace);
synchronized (monitor) {
final Map<String, Set<ExecutorService>> subResourceMap = resourcesManager.get(namespace);
if (subResourceMap.containsKey(group)) {
subResourceMap.get(group).remove(executor);
}
}
}
}
/**
* Destroys all thread pool resources under this namespace.
*
* @param namespace namespace
*/
public void destroy(final String namespace) {
final Object monitor = lockers.get(namespace);
if (monitor == null) {
return;
}
synchronized (monitor) {
Map<String, Set<ExecutorService>> subResource = resourcesManager.get(namespace);
if (subResource == null) {
return;
}
for (Map.Entry<String, Set<ExecutorService>> entry : subResource.entrySet()) {
for (ExecutorService executor : entry.getValue()) {
ThreadUtils.shutdownThreadPool(executor);
}
}
resourcesManager.get(namespace).clear();
resourcesManager.remove(namespace);
}
}
/**
* This namespace destroys all thread pool resources under the grouping.
*
* @param namespace namespace
* @param group group
*/
public void destroy(final String namespace, final String group) {
final Object monitor = lockers.get(namespace);
if (monitor == null) {
return;
}
synchronized (monitor) {
Map<String, Set<ExecutorService>> subResource = resourcesManager.get(namespace);
if (subResource == null) {
return;
}
Set<ExecutorService> waitDestroy = subResource.get(group);
for (ExecutorService executor : waitDestroy) {
ThreadUtils.shutdownThreadPool(executor);
}
resourcesManager.get(namespace).remove(group);
}
}
/**
* Shutdown thread pool manager.
*/
public static void shutdown() {
if (!CLOSED.compareAndSet(false, true)) {
return;
}
Set<String> namespaces = INSTANCE.resourcesManager.keySet();
for (String namespace : namespaces) {
INSTANCE.destroy(namespace);
}
}
@JustForTest
public Map<String, Map<String, Set<ExecutorService>>> getResourcesManager() {
return resourcesManager;
}
@JustForTest
public Map<String, Object> getLockers() {
return lockers;
}
}
下面是ThreadUtils的代码
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.common.utils;
import org.slf4j.Logger;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
/**
* Thread utils.
*
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
*/
public final class ThreadUtils {
private static final int THREAD_MULTIPLER = 2;
/**
* Wait.
*
* @param object load object
*/
public static void objectWait(Object object) {
try {
object.wait();
} catch (InterruptedException ignore) {
Thread.interrupted();
}
}
/**
* Sleep.
*
* @param millis sleep millisecond
*/
public static void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
public static void countDown(CountDownLatch latch) {
Objects.requireNonNull(latch, "latch");
latch.countDown();
}
/**
* Await count down latch.
*
* @param latch count down latch
*/
public static void latchAwait(CountDownLatch latch) {
try {
latch.await();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
/**
* Await count down latch with timeout.
*
* @param latch count down latch
* @param time timeout time
* @param unit time unit
*/
public static void latchAwait(CountDownLatch latch, long time, TimeUnit unit) {
try {
latch.await(time, unit);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
/**
* Through the number of cores, calculate the appropriate number of threads; 1.5-2 times the number of CPU cores.
*
* @return thread count
*/
public static int getSuitableThreadCount() {
return getSuitableThreadCount(THREAD_MULTIPLER);
}
/**
* Through the number of cores, calculate the appropriate number of threads.
*
* @param threadMultiple multiple time of cores
* @return thread count
*/
public static int getSuitableThreadCount(int threadMultiple) {
final int coreCount = PropertyUtils.getProcessorsCount();
int workerCount = 1;
while (workerCount < coreCount * threadMultiple) {
workerCount <<= 1;
}
return workerCount;
}
public static void shutdownThreadPool(ExecutorService executor) {
shutdownThreadPool(executor, null);
}
/**
* Shutdown thread pool.
*
* @param executor thread pool
* @param logger logger
*/
public static void shutdownThreadPool(ExecutorService executor, Logger logger) {
executor.shutdown();
int retry = 3;
while (retry > 0) {
retry--;
try {
if (executor.awaitTermination(100, TimeUnit.MILLISECONDS)) {
return;
}
} catch (InterruptedException e) {
executor.shutdownNow();
Thread.interrupted();
} catch (Throwable ex) {
if (logger != null) {
logger.error("ThreadPoolManager shutdown executor has error : ", ex);
}
}
}
executor.shutdownNow();
}
public static void addShutdownHook(Runnable runnable) {
Runtime.getRuntime().addShutdownHook(new Thread(runnable));
}
}