JAVA 多线程应用总结<一>
一、ThreadLocal 线程本地变量,ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。是一个时间->空间的转换(内存的占用会比不使用ThreadLocal要大).
- 每个线程Thread内部有一个ThreadLocal.ThreadLocalMap类型的成员变量threadLocals,这个threadLocals就是用来存储实际的变量副本的,键值为当前ThreadLocal变量,value为变量副本(即T类型的变量)
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }
void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }
- 在使用get()前需要先set()否则空指针。除非在初始化时进行
/** * 控制各线程记录开关 */ public final static ThreadLocal<Boolean> LOCAL =new ThreadLocal<Boolean>(){ @Override protected Boolean initialValue() { return true; } };
或
/** * 控制各线程记录开关 */ public final static ThreadLocal<Boolean> LOCAL =ThreadLocal.withInitial(()->true);
- 在Thread中使用完ThreadLocal对象后,一定要记得调用ThreadLocal的remove方法,进行手动清除。
MonitorConstant.LOCAL.remove();
二、ThreadPoolExecutor 线程池
/** * workQueue(任务队列) : 用于保存等待执行的任务的阻塞队列 * 1) ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,按FIFO原则进行排序 * 2) LinkedBlockingQueue:一个基于链表结构的阻塞队列,吞吐量高于ArrayBlockingQueue * 静态工厂方法Excutors.newFixedThreadPool()使用了这个队列 * 3)SynchronousQueue: 一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量高于LinkedBlockingQueue * 静态工厂方法Excutors.newCachedThreadPool()使用了这个队列 * 4)PriorityBlockingQueue:一个具有优先级的无限阻塞队列。 * * handler : 线程池对拒绝任务的处理策略。 * 1) ThreadPoolExecutor.AbortPolicy 丢弃任务,并抛出 RejectedExecutionException 异常。 * 2) ThreadPoolExecutor.CallerRunsPolicy:该任务被线程池拒绝,由调用 execute方法的线程执行该任务。 * 3) ThreadPoolExecutor.DiscardOldestPolicy : 抛弃队列最前面的任务,然后重新尝试执行任务。 * 4) ThreadPoolExecutor.DiscardPolicy,丢弃任务,不过也不抛出异常。 */ private static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), new NotifierThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
三、Semaphore(计数信号量) 每个acquire方法阻塞,直到有一个许可证可以获得然后拿走一个许可证;每个release方法增加一个许可证,这可能会释放一个阻塞的acquire方法 ---------> Semaphore经常用于限制获取某种资源的线程数量。
private static final Semaphore SEMAPHORE = new Semaphore(POOL_SIZE); public static void startJob(Callback event) { try { SEMAPHORE.acquire(); } catch ( InterruptedException ignored ) {} threadPoolExecutor.execute(() -> { int retry = 0; boolean loop; do { try { if ( event.call() ) { loop = false; } else { throw new Exception(" event 's call() return false "); } } catch ( Exception e ) { loop = true; if ( retry >= TIME_BLOCK.length ) { logger.error(" a Notifier died. ", e); loop = false; } else { try { Thread.sleep(TIME_BLOCK[retry++]); } catch ( InterruptedException ignored ) {} } } } while ( loop ); SEMAPHORE.release(); }); }