package com.brightgenerous.commons.concurrent; import static com.brightgenerous.commons.ObjectUtils.*; import java.io.Serializable; import java.lang.ref.SoftReference; import java.util.HashSet; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import com.brightgenerous.lang.Args; public class ThreadUtils implements Serializable { private static final long serialVersionUID = 1485395160469358267L; static class InstanceKey implements Serializable { private static final long serialVersionUID = -5571606798438371038L; private final Class<?> clazz; private final String key; public InstanceKey(Class<?> clazz, String key) { this.clazz = clazz; this.key = key; } @Override public int hashCode() { final int multiplier = 37; int result = 17; result = (multiplier * result) + hashCodeEscapeNull(clazz); result = (multiplier * result) + hashCodeEscapeNull(key); return result; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (!(obj instanceof InstanceKey)) { return false; } InstanceKey other = (InstanceKey) obj; if (!equalsEscapeNull(clazz, other.clazz)) { return false; } if (!equalsEscapeNull(key, other.key)) { return false; } return true; } } private transient volatile boolean init; private transient volatile ExecutorService executorService; private Integer threads; protected ThreadUtils() { this(null); } protected ThreadUtils(Integer threads) { setIfGreater(threads); } public static ThreadUtils get() { return get((Integer) null); } public static ThreadUtils get(Integer threads) { return get((Class<?>) null, threads); } public static ThreadUtils get(Class<?> clazz) { return get(clazz, null); } public static ThreadUtils get(Class<?> clazz, Integer threads) { return getInstance(clazz, null, threads); } public static ThreadUtils get(String key) { return get(key, null); } public static ThreadUtils get(String key, Integer threads) { return getInstance(null, key, threads); } // maybe, it may not should use SoftReference. private static volatile Map<InstanceKey, SoftReference<ThreadUtils>> cache; protected static ThreadUtils getInstance(Class<?> clazz, String key, Integer threads) { if (cache == null) { synchronized (ThreadUtils.class) { if (cache == null) { cache = new ConcurrentHashMap<>(); } } } InstanceKey ik = new InstanceKey(clazz, key); SoftReference<ThreadUtils> sr = cache.get(ik); ThreadUtils ret; if (sr != null) { ret = sr.get(); if (ret != null) { ret.setIfGreater(threads); return ret; } Set<InstanceKey> dels = new HashSet<>(); for (Entry<InstanceKey, SoftReference<ThreadUtils>> entry : cache.entrySet()) { if (entry.getValue().get() == null) { dels.add(entry.getKey()); } } for (InstanceKey del : dels) { cache.remove(del); } } ret = new ThreadUtils(threads); cache.put(ik, new SoftReference<>(ret)); return ret; } protected void setIfGreater(Integer threads) { if (threads != null) { Args.greaterEqual(Integer.valueOf(0), threads, "threads"); synchronized (this) { if ((this.threads != threads) && ((this.threads == null) || (this.threads.compareTo(threads) < 0))) { this.threads = threads; init = false; } } } } protected ExecutorService getExecutorService() { if (!init) { synchronized (this) { if (!init) { if ((threads == null) || (threads.intValue() < 1)) { executorService = null; } else { executorService = Executors.newFixedThreadPool(threads.intValue()); } init = true; } } } return executorService; } public void execute(Runnable runnable) { Args.notNull(runnable, "runnable"); ExecutorService executerService = getExecutorService(); if (executerService != null) { executorService.execute(runnable); } else { runnable.run(); } } }