import java.util.LinkedHashMap;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;/**
* LruHashMap is an extension of Java's HashMap, which has a bounded size();
* When it reaches that size, each time a new element is added, the least recently used (LRU) entry is removed.
* Java makes it very easy to implement LruHashMap - all its functionality is already available from LinkedHashMap,
* and we just need to configure that properly.
* Note that LruHashMap is thread safe
*/publicclassLruHashMap<K, V>extendsLinkedHashMap<K, V>{privatestaticfinallong serialVersionUID =-5167631809472116969L;privatestaticfinalfloat DEFAULT_LOAD_FACTOR =0.75f;privatestaticfinalint DEFAULT_MAX_CAPACITY =1000;privatefinal Lock lock =newReentrantLock();privatevolatileint maxCapacity;publicLruHashMap(){this(DEFAULT_MAX_CAPACITY);}publicLruHashMap(int maxCapacity){super(16, DEFAULT_LOAD_FACTOR,true);this.maxCapacity = maxCapacity;}@OverrideprotectedbooleanremoveEldestEntry(java.util.Map.Entry<K, V> eldest){returnsize()> maxCapacity;}@OverridepublicbooleancontainsKey(Object key){try{
lock.lock();returnsuper.containsKey(key);}finally{
lock.unlock();}}@Overridepublic V get(Object key){try{
lock.lock();returnsuper.get(key);}finally{
lock.unlock();}}@Overridepublic V put(K key, V value){try{
lock.lock();returnsuper.put(key, value);}finally{
lock.unlock();}}@Overridepublic V remove(Object key){try{
lock.lock();returnsuper.remove(key);}finally{
lock.unlock();}}@Overridepublicintsize(){try{
lock.lock();returnsuper.size();}finally{
lock.unlock();}}@Overridepublicvoidclear(){try{
lock.lock();super.clear();}finally{
lock.unlock();}}publicintgetMaxCapacity(){return maxCapacity;}publicvoidsetMaxCapacity(int maxCapacity){this.maxCapacity = maxCapacity;}}
package com.xxxx.faceadd.jetcache;import com.google.common.collect.Lists;import java.util.ArrayDeque;import java.util.Deque;import java.util.List;import java.util.Map;import java.util.concurrent.ConcurrentHashMap;import java.util.concurrent.locks.ReentrantLock;publicclassLRUCache<K, V>{privatefinalint limit;privatefinal Map<K, V> cache;privatefinal Deque<K> deque;privatefinal ReentrantLock reentrantLock =newReentrantLock();privatestaticfinalint DEFAULT_CAPACITY =16;privatestaticfinalfloat DEFAULT_LOAD_FACTOR =0.75f;publicLRUCache(int limit){this.limit = limit;
deque =newArrayDeque<>(limit);
cache =newConcurrentHashMap<>(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR);}publicLRUCache(int limit,int capacity,float loadFactor){this.limit = limit;
deque =newArrayDeque<>(limit);
cache =newConcurrentHashMap<>(capacity, loadFactor);}publicvoidput(K key, V value){
V v = cache.get(key);
reentrantLock.lock();try{if(v == null){
cache.put(key, value);
deque.removeFirstOccurrence(key);
deque.addFirst(key);}else{
deque.removeFirstOccurrence(key);
deque.addFirst(key);}if(size()> limit){
K keys = deque.removeLast();if(keys != null){
cache.remove(keys);}}}finally{
reentrantLock.unlock();}}public V get(K key){
V v = cache.get(key);if(v != null){
reentrantLock.lock();try{
deque.removeFirstOccurrence(key);
deque.addFirst(key);}finally{
reentrantLock.unlock();}}return v;}publicintsize(){return cache.size();}@Overridepublic String toString(){
List<String> values = Lists.newArrayListWithExpectedSize(limit);
reentrantLock.lock();try{for(K k :this.deque){
V v = cache.get(k);
values.add(k.toString()+" -> "+ v.toString());}}finally{
reentrantLock.unlock();}return values.toString();}}
五、网络相关工具类
import lombok.extern.slf4j.Slf4j;import java.io.IOException;import java.lang.management.ManagementFactory;import java.net.*;import java.util.Enumeration;import java.util.LinkedHashMap;import java.util.Map;import java.util.Random;import java.util.regex.Pattern;/**
* NetUtils
*/@Slf4jpublicclassNetUtils{publicstaticfinal String LOCALHOST ="127.0.0.1";publicstaticfinal String ANY_HOST ="0.0.0.0";privatestaticfinalint RND_PORT_START =30000;privatestaticfinalint RND_PORT_RANGE =10000;privatestaticfinal Random RANDOM =newRandom(System.currentTimeMillis());privatestaticfinalint MIN_PORT =0;privatestaticfinalint MAX_PORT =65535;privatestaticfinal Pattern ADDRESS_PATTERN = Pattern.compile("^\\d{1,3}(\\.\\d{1,3}){3}\\:\\d{1,5}$");privatestaticfinal Pattern LOCAL_IP_PATTERN = Pattern.compile("127(\\.\\d{1,3}){3}$");privatestaticfinal Pattern IP_PATTERN = Pattern.compile("\\d{1,3}(\\.\\d{1,3}){3,5}$");privatestaticfinal Map<String, String> HOST_NAME_CACHE =newLinkedHashMap<>();privatestaticvolatile InetAddress LOCAL_ADDRESS = null;privatestaticvolatile String PROCESS_ID = null;publicstaticintgetAvailablePort(){try(ServerSocket ss =newServerSocket()){
ss.bind(null);return ss.getLocalPort();}catch(IOException e){return RND_PORT_START + RANDOM.nextInt(RND_PORT_RANGE);}}publicstaticintgetAvailablePort(int port){if(port <=0){returngetAvailablePort();}for(int i = port; i < MAX_PORT; i++){try(ServerSocket ss =newServerSocket(i)){return i;}catch(IOException e){// continue}}return port;}publicstaticbooleanisInvalidPort(int port){return port <= MIN_PORT || port > MAX_PORT;}publicstaticbooleanisValidAddress(String address){return ADDRESS_PATTERN.matcher(address).matches();}publicstaticbooleanisLocalHost(String host){return host != null
&&(LOCAL_IP_PATTERN.matcher(host).matches()||"localhost".equalsIgnoreCase(host));}publicstaticbooleanisAnyHost(String host){return"0.0.0.0".equals(host);}publicstaticbooleanisInvalidLocalHost(String host){return host == null
|| host.length()==0||"localhost".equalsIgnoreCase(host)||"0.0.0.0".equals(host)||(LOCAL_IP_PATTERN.matcher(host).matches());}publicstaticbooleanisValidLocalHost(String host){return!isInvalidLocalHost(host);}publicstatic InetSocketAddress getLocalSocketAddress(String host,int port){returnisInvalidLocalHost(host)?newInetSocketAddress(port):newInetSocketAddress(host, port);}privatestaticbooleanisValidAddress(InetAddress address){if(address == null || address.isLoopbackAddress()){returnfalse;}
String name = address.getHostAddress();return(name != null
&&!ANY_HOST.equals(name)&&!LOCALHOST.equals(name)&& IP_PATTERN.matcher(name).matches());}publicstatic String getLocalHost(){
InetAddress address =getLocalAddress();return address == null ? LOCALHOST : address.getHostAddress();}/**
* Find first valid IP from local network card
*
* @return first valid local IP
*/publicstatic InetAddress getLocalAddress(){if(LOCAL_ADDRESS != null){return LOCAL_ADDRESS;}
InetAddress localAddress =getLocalAddress0();
LOCAL_ADDRESS = localAddress;return localAddress;}privatestatic InetAddress getLocalAddress0(){
InetAddress localAddress = null;try{
localAddress = InetAddress.getLocalHost();if(isValidAddress(localAddress)){return localAddress;}}catch(Throwable e){
log.warn("Failed to retrieving ip address, "+ e.getMessage(), e);}try{
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();if(interfaces != null){while(interfaces.hasMoreElements()){try{
NetworkInterface network = interfaces.nextElement();
Enumeration<InetAddress> addresses = network.getInetAddresses();while(addresses.hasMoreElements()){try{
InetAddress address = addresses.nextElement();if(isValidAddress(address)){return address;}}catch(Throwable e){
log.warn("Failed to retrieving ip address, "+ e.getMessage(), e);}}}catch(Throwable e){
log.warn("Failed to retrieving ip address, "+ e.getMessage(), e);}}}}catch(Throwable e){
log.warn("Failed to retrieving ip address, "+ e.getMessage(), e);}
log.error("Could not get local host ip address, will use 127.0.0.1 instead.");return localAddress;}publicstatic String getHostName(String address){try{int i = address.indexOf(':');if(i >-1){
address = address.substring(0, i);}
String hostname = HOST_NAME_CACHE.get(address);if(hostname != null && hostname.length()>0){return hostname;}
InetAddress inetAddress = InetAddress.getByName(address);if(inetAddress != null){
hostname = inetAddress.getHostName();
HOST_NAME_CACHE.put(address, hostname);return hostname;}}catch(Throwable e){// ignore}return address;}publicstatic String getIpByHost(String hostName){try{return InetAddress.getByName(hostName).getHostAddress();}catch(UnknownHostException e){return hostName;}}publicstatic String toAddressString(InetSocketAddress address){return address.getAddress().getHostAddress()+":"+ address.getPort();}publicstatic InetSocketAddress toAddress(String address){int i = address.indexOf(':');
String host;int port;if(i >-1){
host = address.substring(0, i);
port = Integer.parseInt(address.substring(i +1));}else{
host = address;
port =0;}returnnewInetSocketAddress(host, port);}publicstatic String getProcessId(){if(PROCESS_ID != null){return PROCESS_ID;}return PROCESS_ID = ManagementFactory.getRuntimeMXBean().getName().split("@")[0];}}
import java.sql.Timestamp;import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent.ScheduledThreadPoolExecutor;import java.util.concurrent.TimeUnit;import java.util.concurrent.atomic.AtomicLong;/**
* ClockUtils
* <p>
* 利用ScheduledExecutorService实现高并发场景下System.currentTimeMillis()的性能问题的优化.
*/publicclassSystemClock{privatestatic AtomicLong nowTime;privatestaticvolatileboolean started =false;/**
* The get string current time
*
* @return string time
*/publicstatic String currentTimeMillisStr(){returnnewTimestamp(currentTimeMillis()).toString();}/**
* The get current time milliseconds
*
* @return long time
*/publicstaticlongcurrentTimeMillis(){if(!started){synchronized(SystemClock.class){if(!started){
nowTime =newAtomicLong(System.currentTimeMillis());
ScheduledExecutorService executorService =newScheduledThreadPoolExecutor(1, r ->{
Thread thread =newThread(r,"system-clock");
thread.setDaemon(true);return thread;});
executorService.scheduleAtFixedRate(()->
nowTime.set(System.currentTimeMillis()),1,1, TimeUnit.MILLISECONDS);
Runtime.getRuntime().addShutdownHook(newThread(executorService::shutdown));
started =true;}}}return nowTime.get();}}
十一、获取系统内存与版本等工具类
import com.sun.management.OperatingSystemMXBean;import lombok.Data;import lombok.ToString;import lombok.extern.slf4j.Slf4j;import javax.management.MBeanServer;import javax.management.ObjectName;import java.io.File;import java.io.Serializable;import java.lang.management.GarbageCollectorMXBean;import java.lang.management.ManagementFactory;import java.math.BigDecimal;import java.net.NetworkInterface;import java.util.ArrayList;import java.util.Enumeration;import java.util.List;/**
* SystemUtils
* <p>
* 1.EnvironmentInfo
* 2.MemoryInfo
* 3.CpuLoadInfo
* 4.DiskInfo
* 5.GarbageCollectorInfo
*/@Slf4jpublicclassSystemUtils{/**
* The collect
*
* @return {@link MetricCollect}
*/publicstatic MetricCollect collect(){
MetricCollect metricCollect =newMetricCollect();
metricCollect.setMemoryInfo(SystemUtils.getMemory());
metricCollect.setCpuLoadInfo(SystemUtils.getCpuLoadInfo());
metricCollect.setDiskInfo(SystemUtils.getDiskInfo());
metricCollect.setGarbageCollectorInfos(SystemUtils.getGarbageCollectorInfo());return metricCollect;}@DatapublicstaticclassMetricCollectimplementsSerializable{privatestaticfinallong serialVersionUID =3465584618686630943L;private SystemUtils.MemoryInfo memoryInfo;private SystemUtils.CpuLoadInfo cpuLoadInfo;private List<DiskInfo> diskInfo;private List<GarbageCollectorInfo> garbageCollectorInfos;}/**
* The get environment info
*
* @return {@link EnvironmentInfo}
*/publicstatic EnvironmentInfo getEnvironment(){
EnvironmentInfo info =newEnvironmentInfo();
info.setOsName(System.getProperty("os.name"));
info.setOsVersion(System.getProperty("os.version"));
info.setOsArch(System.getProperty("os.arch"));
info.setJvmName(System.getProperty("java.vm.name"));
info.setJvmVersion(System.getProperty("java.runtime.version"));
info.setCpuCore(Runtime.getRuntime().availableProcessors());try{
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();if(interfaces != null){while(interfaces.hasMoreElements()){try{
NetworkInterface network = interfaces.nextElement();if(network != null){
info.setNetworkName(network.getName());
info.setNetworkDisplayName(network.getDisplayName());}}catch(Throwable e){
log.warn("Failed to retrieving ip address, "+ e.getMessage(), e);}}}}catch(Throwable e){
log.warn("Failed to retrieving ip address, "+ e.getMessage(), e);}return info;}/**
* The get memory info
*
* @return {@link MemoryInfo}
*/publicstatic MemoryInfo getMemory(){int mb =1024*1024;
Runtime runtime = Runtime.getRuntime();
MemoryInfo memoryInfo =newMemoryInfo();// JVMdouble freeMemory =(double) runtime.freeMemory()/ mb;double maxMemory =(double) runtime.maxMemory()/ mb;double totalMemory =(double) runtime.totalMemory()/ mb;double usedMemory = totalMemory - freeMemory;double percentUsed =(usedMemory / maxMemory)*100.0;
usedMemory =newBigDecimal(usedMemory).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
maxMemory =newBigDecimal(maxMemory).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
percentUsed =newBigDecimal(percentUsed).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
memoryInfo.setUsedMemory(usedMemory);
memoryInfo.setMaxMemory(maxMemory);
memoryInfo.setPercentUsed(percentUsed);// System
OperatingSystemMXBean osBean =(OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();double totalPhysicalMemory =(double) osBean.getTotalPhysicalMemorySize()/ mb;double freePhysicalMemory =(double) osBean.getFreePhysicalMemorySize()/ mb;double committedVirtualMemory =(double) osBean.getCommittedVirtualMemorySize()/ mb;
totalPhysicalMemory =newBigDecimal(totalPhysicalMemory).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
freePhysicalMemory =newBigDecimal(freePhysicalMemory).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
committedVirtualMemory =newBigDecimal(committedVirtualMemory).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
memoryInfo.setTotalPhysicalMemory(totalPhysicalMemory);
memoryInfo.setFreePhysicalMemory(freePhysicalMemory);
memoryInfo.setCommittedVirtualMemory(committedVirtualMemory);return memoryInfo;}/**
* The get cpu load info
*
* @return {@link CpuLoadInfo}
*/publicstatic CpuLoadInfo getCpuLoadInfo(){try{
MBeanServer beanServer = ManagementFactory.getPlatformMBeanServer();
ObjectName objectName = ObjectName.getInstance("java.lang:type=OperatingSystem");// read process cpu load
Double processCpuLoad =getAttributeValue(beanServer, objectName,"ProcessCpuLoad");// read system cpu load
Double systemCpuLoad =getAttributeValue(beanServer, objectName,"SystemCpuLoad");if(processCpuLoad != null || systemCpuLoad != null){
CpuLoadInfo cpuLoadInfo =newCpuLoadInfo();
cpuLoadInfo.setProcessCpuLoad(processCpuLoad);
cpuLoadInfo.setSystemCpuLoad(systemCpuLoad);return cpuLoadInfo;}}catch(Exception e){
log.error(e.getMessage(), e);}return null;}/**
* The get disk info
*
* @return {@link DiskInfo}
*/publicstatic List<DiskInfo>getDiskInfo(){double mb =1024*1024;
List<DiskInfo> diskInfoList =newArrayList<>();
File[] disks = File.listRoots();for(File file : disks){
DiskInfo diskInfo =newDiskInfo();
diskInfo.setPath(file.getPath());// 空闲空间
diskInfo.setFreeSpace(newBigDecimal(
file.getFreeSpace()/ mb).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());// 可用空间
diskInfo.setUsableSpace(newBigDecimal(
file.getUsableSpace()/ mb).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());// 总空间
diskInfo.setTotalSpace(newBigDecimal(
file.getTotalSpace()/ mb).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
diskInfoList.add(diskInfo);}return diskInfoList;}/**
* The get garbage collector info
*
* @return {@link GarbageCollectorInfo}
*/publicstatic List<GarbageCollectorInfo>getGarbageCollectorInfo(){
List<GarbageCollectorInfo> garbageCollectorInfoList =newArrayList<>();
List<GarbageCollectorMXBean> gcBeans = ManagementFactory.getGarbageCollectorMXBeans();for(GarbageCollectorMXBean gcBean : gcBeans){
GarbageCollectorInfo garbageCollectorInfo =newGarbageCollectorInfo();
garbageCollectorInfo.setName(gcBean.getName());
garbageCollectorInfo.setCollectionTime(gcBean.getCollectionTime());
garbageCollectorInfo.setCollectionCount(gcBean.getCollectionCount());
garbageCollectorInfoList.add(garbageCollectorInfo);}return garbageCollectorInfoList;}privatestatic Double getAttributeValue(MBeanServer beanServer, ObjectName objectName, String attribute)throws Exception {
Object cpuLoadObject = beanServer.getAttribute(objectName, attribute);if(cpuLoadObject == null){return null;}double cpuLoadValue =(double) cpuLoadObject;if(cpuLoadValue <0){// usually takes a couple of seconds before we get real valuesreturn0.00;}// returns a percentage value with 1 decimal point precisionreturnnewBigDecimal(cpuLoadValue *100).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();}/**
* EnvironmentInfo
*/@Data@ToStringpublicstaticclassEnvironmentInfoimplementsSerializable{privatestaticfinallong serialVersionUID =-9055644935967288508L;private String osName;private String osVersion;private String osArch;private String jvmName;private String jvmVersion;private Integer cpuCore;private String networkName;private String networkDisplayName;}/**
* MemoryInfo
*/@Data@ToStringpublicstaticclassMemoryInfoimplementsSerializable{privatestaticfinallong serialVersionUID =-6078242692181489693L;// === JVM/**
* Used memory(MB)
*/privatedouble usedMemory;/**
* Max memory(MB)
*/privatedouble maxMemory;/**
* Percent used(%)
*/privatedouble percentUsed;// === Systemprivatedouble totalPhysicalMemory;privatedouble freePhysicalMemory;privatedouble committedVirtualMemory;}/**
* CpuLoadInfo
*/@Data@ToStringpublicstaticclassCpuLoadInfoimplementsSerializable{privatestaticfinallong serialVersionUID =-7983527685877649306L;/**
* Process CPU load
*/private Double processCpuLoad;/**
* System CPU load
*/private Double systemCpuLoad;}/**
* DiskInfo
*/@Data@ToStringpublicstaticclassDiskInfoimplementsSerializable{privatestaticfinallong serialVersionUID =1486150261930978720L;private String path;private Double freeSpace;private Double usableSpace;private Double totalSpace;}/**
* GarbageCollectorInfo
*/@Data@ToStringpublicstaticclassGarbageCollectorInfoimplementsSerializable{privatestaticfinallong serialVersionUID =-6536126923166050353L;private String name;private Long collectionTime;private Long collectionCount;}}
十二、三元结构体
/**
* 三元结构体
*
* @param <F>
* @param <S>
* @param <T>
*/publicclassTriple<F, S, T>{private F first;private S second;private T third;publicTriple(F first, S second, T third){this.first = first;this.second = second;this.third = third;}public F getFirst(){return first;}publicvoidsetFirst(F first){this.first = first;}public S getSecond(){return second;}publicvoidsetSecond(S second){this.second = second;}public T getThird(){return third;}publicvoidsetThird(T third){this.third = third;}@Overridepublic String toString(){return"Triple{"+"first="+ first +", second="+ second +", third="+ third +'}';}}
十三、二元体结构
/**
* 二元体结构
*/publicclassPair<F, S>{privatefinal F first;privatefinal S second;publicPair(F first, S second){this.first = first;this.second = second;}public F getFirst(){return first;}public S getSecond(){return second;}@Overridepublic String toString(){return"Pair{"+"first="+ first +", second="+ second +'}';}}
十四、使用PriorityQueue作为任务工作队列 实现Timer工具
import org.slf4j.Logger;import org.slf4j.LoggerFactory;import java.util.Date;import java.util.PriorityQueue;import java.util.concurrent.atomic.AtomicInteger;/**
* jdk Timer工具的另一个实现
* 区别:
* 内部直接使用PriorityQueue作为任务工作队列
* 运行过程中,若有一个task发生异常,整个Timer定时器不会关闭(jdk自带的timer会关闭)
* 任务单元直接使用Runnable接口
*/publicclassTimer{finalstatic Logger logger = LoggerFactory.getLogger(Timer.class);private PriorityQueue<TimerTask> queue;privatefinal TimerThread thread;privatestaticfinal AtomicInteger nextSerialNumber =newAtomicInteger(0);privatestaticintserialNumber(){return nextSerialNumber.getAndIncrement();}publicTimer(){this("Timer-"+serialNumber());}publicTimer(boolean daemon){this("Timer-"+serialNumber(), daemon);}publicTimer(String threadName){this.queue =newPriorityQueue<>();this.thread =newTimerThread(this.queue);this.thread.setName(threadName);this.thread.start();}publicTimer(String threadName,boolean daemon){this.queue =newPriorityQueue();this.thread =newTimerThread(this.queue);this.thread.setName(threadName);this.thread.setDaemon(daemon);this.thread.start();}publicvoidschedule(Runnable task,long delay){if(delay <0L){thrownewIllegalArgumentException("Negative delay.");}else{this.schedule(task, System.currentTimeMillis()+ delay,0L);}}publicvoidschedule(Runnable task, Date start){this.schedule(task, start.getTime(),0L);}publicvoidscheduleAtFixedRate(Runnable task,long delay,long period){if(delay <0L){thrownewIllegalArgumentException("Negative delay.");}elseif(period <=0L){thrownewIllegalArgumentException("Non-positive period.");}else{this.schedule(task, System.currentTimeMillis()+ delay, period);}}publicvoidscheduleAtFixedRate(Runnable task, Date start,long period){if(period <=0L){thrownewIllegalArgumentException("Non-positive period.");}else{this.schedule(task, start.getTime(), period);}}privatevoidschedule(Runnable task,long time,long period){if(time <0L){thrownewIllegalArgumentException("Illegal execution time.");}else{if(Math.abs(period)>4611686018427387903L){
period >>=1;}
TimerTask timerTask =newTimerTask(task);synchronized(this.queue){if(!this.thread.run){thrownewIllegalStateException("Timer already cancelled.");}else{synchronized(timerTask.lock){if(timerTask.state !=0){thrownewIllegalStateException("Task already scheduled or cancelled");}
timerTask.nextExecutionTime = time;
timerTask.period = period;
timerTask.state = TimerTask.SCHEDULED;}this.queue.add(timerTask);if(this.queue.peek()== timerTask){this.queue.notify();}}}}}publicvoidcancel(){
PriorityQueue<TimerTask> vars =this.queue;synchronized(this.queue){this.thread.run =false;this.queue.clear();this.queue.notify();}}}classTimerThreadextendsThread{boolean run =true;private PriorityQueue<TimerTask> queue;publicTimerThread(PriorityQueue<TimerTask> queue){this.queue = queue;}@Overridepublicvoidrun(){try{mainLoop();}finally{// Someone killed this Thread, behave as if Timer cancelledsynchronized(queue){
run =false;// Eliminate obsolete references
queue.clear();}}}/**
* The main timer loop. (See class comment.)
*/privatevoidmainLoop(){while(true){try{
TimerTask task;boolean taskFired;synchronized(queue){// Wait for queue to become non-emptywhile(queue.isEmpty()&& run){
queue.wait();}if(queue.isEmpty()){break;// Queue is empty and will forever remain; die}// Queue nonempty; look at first evt and do the right thinglong currentTime, executionTime;
task = queue.peek();synchronized(task.lock){if(task.state == TimerTask.CANCELLED){
queue.poll();continue;// No action required, poll queue again}
currentTime = System.currentTimeMillis();
executionTime = task.nextExecutionTime;if(taskFired =(executionTime<=currentTime)){
task = queue.poll();// Non-repeating, removeif(task.period ==0){
task.state = TimerTask.EXECUTED;}else{// Repeating task, reschedulelong nextExecTime = task.period <0?
currentTime - task.period
: executionTime + task.period;
task.nextExecutionTime = nextExecTime;
queue.add(task);}}}// Task hasn't yet fired; waitif(!taskFired){
queue.wait(executionTime - currentTime);}}// Task fired; run it, holding no locksif(taskFired){try{
task.run();}catch(Exception e){
Timer.logger.error("timer任务执行异常", e);}}}catch(InterruptedException e){// ignore it}}}}classTimerTaskimplementsRunnable, Comparable<TimerTask>{private Runnable task;final Object lock =newObject();int state = VIRGIN;staticfinalint VIRGIN =0;staticfinalint SCHEDULED =1;staticfinalint EXECUTED =2;staticfinalint CANCELLED =3;long nextExecutionTime;long period =0;TimerTask(Runnable task){this.task = task;}@OverridepublicintcompareTo(TimerTask timerTask){if(timerTask.nextExecutionTime >this.nextExecutionTime){return-1;}if(timerTask.nextExecutionTime <this.nextExecutionTime){return1;}return0;}@Overridepublicvoidrun(){
task.run();}}