-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathVirtual.java
95 lines (83 loc) · 2.01 KB
/
Virtual.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import java.util.*;
import java.util.concurrent.*;
public class Virtual implements Time {
private ScheduleMap<Semaphore> _queue;
private int _threads;
private Semaphore _lock;
private long _clock;
private int _jitter;
private Random _rand;
public Virtual(int jitter) {
_jitter = jitter;
_rand = new Random();
_clock = System.currentTimeMillis();
_lock = new Semaphore(1);
_threads = 0;
_queue = new ScheduleMap<>();
}
private void unregisterThread() {
try {
_lock.acquire();
} catch (Exception e) {}
_threads--;
wakeUpNextIfNoneActive();
_lock.release();
}
private void registerThread() {
try {
_lock.acquire();
} catch (Exception e) {}
_threads++;
_lock.release();
}
public void sleep(long millis) {
try {
_lock.acquire();
} catch (Exception e) {}
var sem = new Semaphore(0);
_queue.put(_clock + millis + (_jitter == 0 ? 0 : _rand.nextInt(_jitter)), sem);
wakeUpNextIfNoneActive();
_lock.release();
try {
sem.acquire();
} catch (Exception e) {}
}
private void wakeUpNextIfNoneActive() {
if (_threads > 0 && _queue.size() == _threads) {
wakeUpNext();
}
}
private void wakeUpNext() {
ScheduleMap.LongEntry<Semaphore> v;
do {
v = _queue.pollFirstEntry();
v.getValue().release();
} while (_queue.size() > 0 && _queue.firstKey() == v.getKey());
_clock = v.getKey();
}
public void releaseNext() {
try {
_lock.acquire();
} catch (Exception e) {}
var sem = new Semaphore(0);
_queue.put(_queue.firstKey(), sem);
wakeUpNextIfNoneActive();
_lock.release();
try {
sem.acquire();
} catch (Exception e) {}
}
public CustomSemaphore freshSemaphore(int size){
return new VirtualSemaphore(this, size);
}
public Thread freshThread(Runnable r) {
registerThread();
return new Thread(() -> {
r.run();
unregisterThread();
});
}
public long currentTimeMillis() {
return _clock;
}
}