001package org.cache2k.impl; 002 003/* 004 * #%L 005 * cache2k core package 006 * %% 007 * Copyright (C) 2000 - 2015 headissue GmbH, Munich 008 * %% 009 * This program is free software: you can redistribute it and/or modify 010 * it under the terms of the GNU General Public License as 011 * published by the Free Software Foundation, either version 3 of the 012 * License, or (at your option) any later version. 013 * 014 * This program is distributed in the hope that it will be useful, 015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 017 * GNU General Public License for more details. 018 * 019 * You should have received a copy of the GNU General Public 020 * License along with this program. If not, see 021 * <http://www.gnu.org/licenses/gpl-3.0.html>. 022 * #L% 023 */ 024 025import java.util.concurrent.RejectedExecutionException; 026import java.util.concurrent.SynchronousQueue; 027import java.util.concurrent.ThreadFactory; 028import java.util.concurrent.ThreadPoolExecutor; 029import java.util.concurrent.TimeUnit; 030import java.util.concurrent.atomic.AtomicInteger; 031 032/** 033 * Provides a shared thread pool used by all caches for background refreshes of expired 034 * entries. The maximum thread size is the processor count times two. 035 * 036 * @author Jens Wilke; created: 2013-06-13 037 */ 038public class CacheRefreshThreadPool { 039 040 public static final int THREAD_COUNT = Runtime.getRuntime().availableProcessors() * 2; 041 private static ThreadPoolExecutor executorForAll; 042 private static int leasedPoolInstances = 0; 043 private static MyStatus status; 044 045 /** 046 * Get an instance of the pool. When the consumer is destroyed it must 047 * call {@link #destroy()} in turn to free resources. 048 */ 049 public synchronized static CacheRefreshThreadPool getInstance() { 050 if (executorForAll == null) { 051 executorForAll = 052 new ThreadPoolExecutor(0, THREAD_COUNT, 053 21, TimeUnit.SECONDS, 054 new SynchronousQueue<Runnable>(), 055 new MyThreadFactory(), 056 new ThreadPoolExecutor.AbortPolicy()); 057 } 058 leasedPoolInstances++; 059 CacheRefreshThreadPool p = new CacheRefreshThreadPool(); 060 p.executor = executorForAll; 061 return p; 062 } 063 064 synchronized static void disposeOne() { 065 leasedPoolInstances--; 066 if (leasedPoolInstances == 0) { 067 executorForAll.shutdown(); 068 executorForAll = null; 069 } 070 } 071 072 private ThreadPoolExecutor executor; 073 074 private CacheRefreshThreadPool() { 075 } 076 077 public boolean submit(Runnable r) { 078 try { 079 executor.execute(r); 080 } catch (RejectedExecutionException e) { 081 return false; 082 } 083 return true; 084 } 085 086 public void destroy() { 087 disposeOne(); 088 executor = null; 089 } 090 091 static class MyThreadFactory implements ThreadFactory { 092 093 AtomicInteger count = new AtomicInteger(); 094 095 @Override 096 public synchronized Thread newThread(Runnable r) { 097 Thread t = new Thread(r, "cache-refresh-" + count.incrementAndGet()); 098 t.setDaemon(true); 099 return t; 100 } 101 102 } 103 104 static class MyStatus { 105 public String toString() { 106 return "CacheRefreshThreadPool(" + 107 "size=" + executorForAll.getPoolSize() + ", " + 108 "sizeLargest=" + executorForAll.getLargestPoolSize() + ", " + 109 "sizeMax=" + executorForAll.getMaximumPoolSize() + ", " + 110 "taskCount=" + executorForAll.getTaskCount() + ")"; 111 } 112 } 113 114}