Chronograph.java revision 77f2b82a2e80af8da52c22d69a76def6d4209757
1package com.android.server.wifi.hotspot2; 2 3import java.util.ArrayList; 4import java.util.HashSet; 5import java.util.Iterator; 6import java.util.List; 7import java.util.Map; 8import java.util.Set; 9import java.util.TreeMap; 10 11public class Chronograph extends Thread { 12 private final Map<Long, Set<AlarmEntry>> mAlarmEntryMap = new TreeMap<Long, Set<AlarmEntry>>(); 13 private boolean mRecalculate; 14 15 private static class AlarmEntry { 16 private final long mAt; 17 private final AlarmHandler mAlarmHandler; 18 private final Object mToken; 19 20 private AlarmEntry(long at, AlarmHandler alarmHandler, Object token) { 21 mAt = at; 22 mAlarmHandler = alarmHandler; 23 mToken = token; 24 } 25 26 private void callout() { 27 mAlarmHandler.wake(mToken); 28 } 29 } 30 31 public Chronograph() 32 { 33 setName("Chronograph"); 34 setDaemon(true); 35 } 36 37 public Object addAlarm(long interval, AlarmHandler handler, Object token) { 38 long at = System.currentTimeMillis() + interval; 39 synchronized (mAlarmEntryMap) { 40 AlarmEntry alarmEntry = new AlarmEntry(at, handler, token); 41 Set<AlarmEntry> entries = mAlarmEntryMap.get(at); 42 if (entries == null) { 43 entries = new HashSet<AlarmEntry>(1); 44 mAlarmEntryMap.put(at, entries); 45 } 46 entries.add(alarmEntry); 47 mRecalculate = true; 48 mAlarmEntryMap.notifyAll(); 49 return alarmEntry; 50 } 51 } 52 53 public boolean cancelAlarm(Object key) { 54 if (key == null || key.getClass() != AlarmEntry.class) { 55 throw new IllegalArgumentException("Not an alarm key"); 56 } 57 58 AlarmEntry alarmEntry = (AlarmEntry)key; 59 60 synchronized (mAlarmEntryMap) { 61 Set<AlarmEntry> entries = mAlarmEntryMap.get(alarmEntry.mAt); 62 if (entries == null) { 63 return false; 64 } 65 if (entries.remove(alarmEntry)) { 66 mRecalculate = true; 67 mAlarmEntryMap.notifyAll(); 68 return true; 69 } 70 return false; 71 } 72 } 73 74 @Override 75 public void run() { 76 77 for(;;) { 78 79 long now = System.currentTimeMillis(); 80 List<Set<AlarmEntry>> pending = new ArrayList<Set<AlarmEntry>>(); 81 82 long nextExpiration = 0; 83 84 synchronized (mAlarmEntryMap) { 85 86 Iterator<Map.Entry<Long,Set<AlarmEntry>>> entries = 87 mAlarmEntryMap.entrySet().iterator(); 88 89 while (entries.hasNext()) { 90 Map.Entry<Long,Set<AlarmEntry>> entry = entries.next(); 91 if (entry.getKey() <= now) { 92 pending.add(entry.getValue()); 93 entries.remove(); 94 } 95 else { 96 nextExpiration = entry.getKey(); 97 break; 98 } 99 } 100 } 101 102 for (Set<AlarmEntry> alarmEntries : pending) { 103 for (AlarmEntry alarmEntry : alarmEntries) { 104 alarmEntry.callout(); 105 } 106 } 107 108 now = System.currentTimeMillis(); 109 110 synchronized (mAlarmEntryMap) { 111 long sleep = nextExpiration - now; 112 while (sleep > 0 && !mRecalculate) { 113 try { 114 mAlarmEntryMap.wait(sleep); 115 } 116 catch (InterruptedException ie) { 117 /**/ 118 } 119 sleep = nextExpiration - System.currentTimeMillis(); 120 } 121 } 122 } 123 } 124 125 public static void main(String[] args) throws InterruptedException{ 126 Chronograph chronograph = new Chronograph(); 127 chronograph.start(); 128 129 chronograph.addAlarm(3000L, new AlarmHandler() { 130 @Override 131 public void wake(Object token) { 132 System.out.println("3: " + token); 133 } 134 }, "3s" ); 135 136 Object key = chronograph.addAlarm(7500L, new AlarmHandler() { 137 @Override 138 public void wake(Object token) { 139 System.out.println("7: " + token); 140 } 141 }, "7.5s" ); 142 143 chronograph.addAlarm(10000L, new AlarmHandler() { 144 @Override 145 public void wake(Object token) { 146 System.out.println("10: " + token); 147 } 148 }, "10.00s" ); 149 150 System.out.println(chronograph.cancelAlarm(key)); 151 152 chronograph.join(); 153 } 154} 155