Java Timer原始碼解析(定時器原始碼解析)
Timer概述
Timer顧名思義就是定時器,用於處理一些需要延時處理的任務,延時時間可能是1s,也可能是5天。
一般使用方式如下:
TimerTask task = new TimerTask() {
@Override
public void run() {
Log.d("test", "timer task test");
}
};
Timer timer = new Timer();
timer.schedule(task, new Date(), 1000);
初始化
從上面程式碼看來,主要是Timer這個類,首先看一下Timer的初始化:
public Timer() {
this("Timer-" + serialNumber());
}
public Timer(String name) {
thread.setName(name);
thread.start();
}
private final TimerThread thread = new TimerThread(queue);
由上面程式碼,我們可以知道,Timer初始化其實就是start了TimerThread這個執行緒,於是我們看一下這個執行緒做的工作:
public void run() {
try {
mainLoop();
} finally {
// Someone killed this Thread, behave as if Timer cancelled
synchronized(queue) {
newTasksMayBeScheduled = false;
queue.clear(); // Eliminate obsolete references
}
}
}
private void mainLoop() {
while (true) {
try {
TimerTask task;
boolean taskFired;
synchronized(queue) {
// Wait for queue to become non-empty
while (queue.isEmpty() && newTasksMayBeScheduled)
queue.wait();
if (queue.isEmpty())
break; // Queue is empty and will forever remain; die
// Queue nonempty; look at first evt and do the right thing
long currentTime, executionTime;
task = queue.getMin();
synchronized(task.lock) {
if (task.state == TimerTask.CANCELLED) {
queue.removeMin();
continue; // No action required, poll queue again
}
currentTime = System.currentTimeMillis();
executionTime = task.nextExecutionTime;
if (taskFired = (executionTime<=currentTime)) {
if (task.period == 0) { // Non-repeating, remove
queue.removeMin();
task.state = TimerTask.EXECUTED;
} else { // Repeating task, reschedule
queue.rescheduleMin(
task.period<0 ? currentTime - task.period
: executionTime + task.period);
}
}
}
if (!taskFired) // Task hasn't yet fired; wait
queue.wait(executionTime - currentTime);
}
if (taskFired) // Task fired; run it, holding no locks
task.run();
} catch(InterruptedException e) {
}
}
}
程式碼不長,也比較容易看懂:
1、檢視任務佇列是否為空,如果為空就阻塞住。
2、獲取佇列中等待時間最少的一個,檢視其狀態是否已被關閉以及是否需要重複執行。
3、如果任務沒有被取消,不需要移除佇列。那麼就判斷其需要執行的時間是否小於等於當前時間,如果小於等於,就通過wait等待到該時間執行,如果大於,那麼就直接run執行。
任務佇列(小根堆)
定時器每次都會觸發時間最小的那個任務,這種取極值的情況用堆非常的合適。
使用堆結構主要快在新增和刪除,其效能都是log(n)。
也就是說在1000個任務的堆中新增和刪除操作都能在10次對比以內完成。
原始碼如下:
class TaskQueue {
private TimerTask[] queue = new TimerTask[128];
private int size = 0;
int size() {
return size;
}
void add(TimerTask task) {
// Grow backing store if necessary
if (size + 1 == queue.length)
queue = Arrays.copyOf(queue, 2*queue.length);
queue[++size] = task;
fixUp(size);
}
TimerTask getMin() {
return queue[1];
}
TimerTask get(int i) {
return queue[i];
}
void removeMin() {
queue[1] = queue[size];
queue[size--] = null; // Drop extra reference to prevent memory leak
fixDown(1);
}
void quickRemove(int i) {
assert i <= size;
queue[i] = queue[size];
queue[size--] = null; // Drop extra ref to prevent memory leak
}
void rescheduleMin(long newTime) {
queue[1].nextExecutionTime = newTime;
fixDown(1);
}
boolean isEmpty() {
return size==0;
}
void clear() {
// Null out task references to prevent memory leak
for (int i=1; i<=size; i++)
queue[i] = null;
size = 0;
}
private void fixUp(int k) {
while (k > 1) {
int j = k >> 1;
if (queue[j].nextExecutionTime <= queue[k].nextExecutionTime)
break;
TimerTask tmp = queue[j]; queue[j] = queue[k]; queue[k] = tmp;
k = j;
}
}
private void fixDown(int k) {
int j;
while ((j = k << 1) <= size && j > 0) {
if (j < size &&
queue[j].nextExecutionTime > queue[j+1].nextExecutionTime)
j++; // j indexes smallest kid
if (queue[k].nextExecutionTime <= queue[j].nextExecutionTime)
break;
TimerTask tmp = queue[j]; queue[j] = queue[k]; queue[k] = tmp;
k = j;
}
}
void heapify() {
for (int i = size/2; i >= 1; i--)
fixDown(i);
}
}
Timer原始碼中的堆實現非常基礎,主要是兩個方法,fixUp()和fixDown(),即上升和下沉。
fixUp:為了保證堆結構,在addTask的時候會使用到上升。
fixDown:在取出最小值的時候,會把堆的最後一個節點放到堆頂,然後執行下沉操作,從而繼續保證堆結構,將堆中剩餘的值的最小值放到堆頂。
相關文章
- Java 定時器 Timer 原始碼分析和使用建議Java定時器原始碼
- Java——HashMap原始碼解析JavaHashMap原始碼
- Java——ArrayList原始碼解析Java原始碼
- Java WeakHashMap 原始碼解析JavaHashMap原始碼
- Java TreeMap 原始碼解析Java原始碼
- SpringBoot原始碼解析-Scheduled定時器的原理Spring Boot原始碼定時器
- Java——LinkedHashMap原始碼解析JavaHashMap原始碼
- 【原始碼解析】- ArrayList原始碼解析,絕對詳細原始碼
- HashMap原始碼解析(java1.8.0)HashMap原始碼Java
- Java集合之Hashtable原始碼解析Java原始碼
- Java 集合Hashtable原始碼深入解析Java原始碼
- Java集合之ArrayList原始碼解析Java原始碼
- Java集合Stack原始碼深入解析Java原始碼
- JAVA集合:LinkedList原始碼解析Java原始碼
- Java集合之HashMap原始碼解析JavaHashMap原始碼
- Java1.8-ArrayList原始碼解析Java原始碼
- Java集合類:AbstractCollection原始碼解析Java原始碼
- Spark原始碼-SparkContext原始碼解析Spark原始碼Context
- CountDownLatch原始碼解析CountDownLatch原始碼
- LeakCanary原始碼解析原始碼
- vuex原始碼解析Vue原始碼
- ArrayBlockQueue原始碼解析BloC原始碼
- AsyncTask原始碼解析原始碼
- CopyOnWriteArrayList原始碼解析原始碼
- Express原始碼解析Express原始碼
- Observer原始碼解析Server原始碼
- SparseArray 原始碼解析原始碼
- RecyclerView原始碼解析View原始碼
- Promise 原始碼解析Promise原始碼
- Koa原始碼解析原始碼
- RateLimiter原始碼解析MIT原始碼
- redux原始碼解析Redux原始碼
- SDWebImage原始碼解析Web原始碼
- CyclicBarrier原始碼解析原始碼
- Semaphore原始碼解析原始碼
- Exchanger原始碼解析原始碼
- AbstractQueuedSynchronizer原始碼解析原始碼
- OKio原始碼解析原始碼