一.引言
今天重读了下之前接触的项目中的代码,略有感悟。主要是几种数据结构或组件的使用和几种设计模式,数据结构的话像google的CacheLoader、延迟队列、阻塞队列等;设计模式的话像单例模式、策略模式、委托模式、管道模式等等。本文主要记录几个数据结构的使用。
二.延迟队列
-
延迟任务
public class DelayTask<T extends Runnable> implements Delayed { private final long time; private final T task; public DelayTask(long time, T task){ this.time = time; this.task = task; } 当getdelay结果为0时才能被取出 @Override public long getDelay(@NotNull TimeUnit unit) { return unit.convert(this.time-System.nanoTime(), TimeUnit.NANOSECONDS); } 取出任务时按照队列内部时间大小排序,时间越小的优先被取出 @Override public int compareTo(@NotNull Delayed o) { DelayTask other = (DelayTask) o; long diff = time - other.time; if(diff>0){ return 1; }else if(diff<0){ return -1; }else { return 0; } } public T getTask(){ return this.task; } }
-
任务
public class DelayWorker implements Runnable{ private String content; public DelayWorker(String content){ this.content = content; } @Override public void run() { System.out.println(this.content); } }
-
管理器
public class CacheManager { private final static int DEFAULT_THREAD_NUM = 4; private ExecutorService executor; private Thread daemonThread; private DelayQueue<DelayTask<?>> delayQueue; private static CacheManager cacheManager = new CacheManager(); public static CacheManager getInstance(){ return cacheManager; } private CacheManager(){ executor = Executors.newFixedThreadPool(DEFAULT_THREAD_NUM); delayQueue = new DelayQueue<>(); init(); } public void init(){ daemonThread = new Thread(() -> { execute(); }); daemonThread.start(); } public void execute(){ while (true){ Map<Thread, StackTraceElement[]> allStackTraces = Thread.getAllStackTraces(); System.out.println("当前活跃线程数量为:" + allStackTraces.size()); System.out.println("当前延迟任务数量为:" + delayQueue.size()); try { DelayTask delayTask = delayQueue.take(); if(delayTask != null){ Runnable task = delayTask.getTask(); if(task != null){ executor.execute(task); } } } catch (InterruptedException e) { e.printStackTrace(); } } } public void put(Runnable task, long time, TimeUnit unit){ long timeout = TimeUnit.NANOSECONDS.convert(time,unit); DelayTask<?> delayTask = new DelayTask<>(timeout,task); delayQueue.put(delayTask); } }
-
测试
public class GuavaCache { public static void main(String[] args) { CacheManager cacheManager = CacheManager.getInstance(); cacheManager.put(new DelayWorker("任务"),1000, TimeUnit.MILLISECONDS); } }
-
输出
当前活跃线程数量为:6 当前延迟任务数量为:0 我的任务
这里注意,明明任务被取出执行了,当前延时任务的数量为什么会是0,不应该是1吗?
- 启东时是先执行的CacheManager的构造方法,由此进入了while循环,执行时还么有向队列中添加延时任务,因此第一次打印的延时任务数量为0,执行到delayqueue的时候发生了阻塞,等待队列元素
- 向队列中添加延时任务后,take方法阻塞结束,取出延时任务执行
三.guava缓存
- 配置缓存
- 通过get获取key对应的value
- 如果缓存中没有该key的话通过load方法计算并添加到缓存中
public class MyGuavaCache extends CacheLoader<Integer,Boolean> {
private LoadingCache<Integer,Boolean> build = CacheBuilder.newBuilder()
.maximumSize(10000)
.expireAfterAccess(60, TimeUnit.MINUTES)
.build(this);
@Override
public Boolean load(Integer num) throws Exception {
if(num % 2 == 1){
return true;
}else{
return false;
}
}
public static void main(String[] args) throws ExecutionException {
MyGuavaCache cache = new MyGuavaCache();
System.out.println(cache.build.get(3));
System.out.println(cache.build.get(4));
}
}
四.阻塞队列
项目中使用的说是阻塞队列实际上更像是阻塞生产者,防止队列产生堆积
public class MyLinkedQueue<T> extends ConcurrentLinkedDeque {
private int limit = 10;
static final float load_factor = 0.5f;
private Object lock = new Object();
private static AtomicLong lockNum = new AtomicLong(0);
public void put(String str){
if(this.size() < limit){
this.add(str);
}else{
//队列元素超上限时,生产者进入等待状态
synchronized (lock){
try {
lock.wait();
lockNum.addAndGet(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
@Override
public T poll(){
//队列有空闲时唤醒生产者
if(limit * load_factor > this.size()){
System.out.println("当前队列数量:" + this.size() + "解锁线程数量:" + lockNum.get());
if(lockNum.get() > 0){
synchronized (lock){
lock.notifyAll();
}
lockNum.set(0);
}
}
return (T) super.poll();
}
public static void main(String[] args) {
MyLinkedQueue<String> queue = new MyLinkedQueue<>();
for(int i=0; i<10; i++){
queue.put("str" + i);
}
for(int i=0; i<10; i++){
System.out.println(queue.poll());
}
}
}
输出
str0
str1
str2
str3
str4
str5
当前队列数量:4解锁线程数量:0
str6
当前队列数量:3解锁线程数量:0
str7
当前队列数量:2解锁线程数量:0
str8
当前队列数量:1解锁线程数量:0
str9