Concurrent Objects
Companion slides for
The Art of Multiprocessor Programming
by Maurice Herlihy & Nir Shavit
Concurrent Computation
Art of Multiprocessor Programming
2
memory
object
object
Objectivism
Art of Multiprocessor Programming
3
FIFO Queue: Enqueue Method
Art of Multiprocessor Programming
4
q.enq( )
FIFO Queue: Dequeue Method
Art of Multiprocessor Programming
5
q.deq()/
A Lock-Based Queue
Art of Multiprocessor Programming
6
class LockBasedQueue<T> {
int head, tail;
T[] items;
Lock lock;
public LockBasedQueue(int capacity) {
head = 0; tail = 0;
lock = new ReentrantLock();
items = (T[]) new Object[capacity];
}
A Lock-Based Queue
Art of Multiprocessor Programming
7
class LockBasedQueue<T> {
int head, tail;
T[] items;
Lock lock;
public LockBasedQueue(int capacity) {
head = 0; tail = 0;
lock = new ReentrantLock();
items = (T[]) new Object[capacity];
}
0
1
capacity-1
2
head
tail
y
z
Queue fields protected by single shared lock
A Lock-Based Queue
Art of Multiprocessor Programming
8
class LockBasedQueue<T> {
int head, tail;
T[] items;
Lock lock;
public LockBasedQueue(int capacity) {
head = 0; tail = 0;
lock = new ReentrantLock();
items = (T[]) new Object[capacity];
}
0
1
capacity-1
2
head
tail
y
z
Initially head = tail
Implementation: Deq
Art of Multiprocessor Programming
9
public T deq() throws EmptyException {
lock.lock();
try {
if (tail == head)
throw new EmptyException();
T x = items[head % items.length];
head++;
return x;
} finally {
lock.unlock();
}
}
0
1
capacity-1
2
head
tail
y
z
Implementation: Deq
Art of Multiprocessor Programming
10
public T deq() throws EmptyException {
lock.lock();
try {
if (tail == head)
throw new EmptyException();
T x = items[head % items.length];
head++;
return x;
} finally {
lock.unlock();
}
}
Method calls
mutually exclusive
0
1
capacity-1
2
head
tail
y
z
0
1
capacity-1
2
head
tail
y
z
Implementation: Deq
Art of Multiprocessor Programming
11
public T deq() throws EmptyException {
lock.lock();
try {
if (tail == head)
throw new EmptyException();
T x = items[head % items.length];
head++;
return x;
} finally {
lock.unlock();
}
}
If queue empty
throw exception
0
1
capacity-1
2
head
tail
y
z
0
1
capacity-1
2
head
tail
y
z
Implementation: Deq
Art of Multiprocessor Programming
12
public T deq() throws EmptyException {
lock.lock();
try {
if (tail == head)
throw new EmptyException();
T x = items[head % items.length];
head++;
return x;
} finally {
lock.unlock();
}
}
Queue not empty:
remove item and update
head
0
1
capacity-1
2
head
tail
y
z
0
1
capacity-1
2
head
tail
y
z
Implementation: Deq
Art of Multiprocessor Programming
13
public T deq() throws EmptyException {
lock.lock();
try {
if (tail == head)
throw new EmptyException();
T x = items[head % items.length];
head++;
return x;
} finally {
lock.unlock();
}
}
Return result
0
1
capacity-1
2
head
tail
y
z
0
1
capacity-1
2
head
tail
y
z
Implementation: Deq
Art of Multiprocessor Programming
14
public T deq() throws EmptyException {
lock.lock();
try {
if (tail == head)
throw new EmptyException();
T x = items[head % items.length];
head++;
return x;
} finally {
lock.unlock();
}
}
Release lock no matter what!
0
1
capacity-1
2
head
tail
y
z
0
1
capacity-1
2
head
tail
y
z
Implementation: Deq
Art of Multiprocessor Programming
15
public T deq() throws EmptyException {
lock.lock();
try {
if (tail == head)
throw new EmptyException();
T x = items[head % items.length];
head++;
return x;
} finally {
lock.unlock();
}
}
Should be correct because
modifications are mutually exclusive…
Now consider the following implementation
Art of Multiprocessor Programming
16
Wait-free 2-Thread Queue
Art of Multiprocessor Programming
17
0
1
capacity-1
2
head
tail
y
z
public class WaitFreeQueue {
int head = 0, tail = 0;
items = (T[]) new Object[capacity];
public void enq(Item x) {
if (tail-head == capacity) throw
new FullException();
items[tail % capacity] = x; tail++;
}
public Item deq() {
if (tail == head) throw
new EmptyException();
Item item = items[head % capacity]; head++;
return item;
}}
Wait-free 2-Thread Queue
Art of Multiprocessor Programming
18
0
1
capacity-1
2
head
tail
y
z
public class WaitFreeQueue {
int head = 0, tail = 0;
items = (T[]) new Object[capacity];
public void enq(Item x) {
if (tail-head == capacity) throw
new FullException();
items[tail % capacity] = x; tail++;
}
public Item deq() {
if (tail == head) throw
new EmptyException();
Item item = items[head % capacity]; head++;
return item;
}}
0
1
capacity-1
2
head
tail
y
z
Wait-free 2-Thread Queue
Art of Multiprocessor Programming
19
public class WaitFreeQueue {
int head = 0, tail = 0;
items = (T[]) new Object[capacity];
public void enq(Item x) {
if (tail-head == capacity) throw
new FullException();
items[tail % capacity] = x; tail++;
}
public Item deq() {
if (tail == head) throw
new EmptyException();
Item item = items[head % capacity]; head++;
return item;
}}
0
1
capacity-1
2
head
tail
y
z
Queue is updated without a lock!
How do we define “correct” when modifications are not mutually exclusive?
Defining concurrent queue implementations
Art of Multiprocessor Programming
20
Correctness and Progress
Art of Multiprocessor Programming
21
Lets begin with correctness
Sequential Specifications
Art of Multiprocessor Programming
22
Pre and PostConditions for Dequeue
Art of Multiprocessor Programming
23
Pre and PostConditions for Dequeue
Art of Multiprocessor Programming
24
Why Sequential Specifications Totally Rock
Art of Multiprocessor Programming
25
What About Concurrent Specifications ?
Art of Multiprocessor Programming
26
Methods Take Time
Art of Multiprocessor Programming
27
time
time
Methods Take Time
Art of Multiprocessor Programming
28
time
invocation 12:00
q.enq(...)
time
Methods Take Time
Art of Multiprocessor Programming
29
time
Method call
invocation 12:00
time
q.enq(...)
Methods Take Time
Art of Multiprocessor Programming
30
time
Method call
invocation 12:00
time
q.enq(...)
Methods Take Time
Art of Multiprocessor Programming
31
time
Method call
invocation 12:00
time
void
response 12:01
q.enq(...)
Sequential vs Concurrent
Art of Multiprocessor Programming
32
Concurrent Methods Take Overlapping Time
Art of Multiprocessor Programming
33
time
time
Concurrent Methods Take Overlapping Time
Art of Multiprocessor Programming
34
time
time
Method call
Concurrent Methods Take Overlapping Time
Art of Multiprocessor Programming
35
time
time
Method call
Method call
Concurrent Methods Take Overlapping Time
Art of Multiprocessor Programming
36
time
time
Method call
Method call
Method call
Sequential vs Concurrent
Art of Multiprocessor Programming
37
Sequential vs Concurrent
Art of Multiprocessor Programming
38
Sequential vs Concurrent
Art of Multiprocessor Programming
39
Panic!
The Big Question
Art of Multiprocessor Programming
40
Intuitively…
Art of Multiprocessor Programming
41
public T deq() throws EmptyException {
lock.lock();
try {
if (tail == head)
throw new EmptyException();
T x = items[head % items.length];
head++;
return x;
} finally {
lock.unlock();
}
}
Intuitively…
Art of Multiprocessor Programming
42
public T deq() throws EmptyException {
lock.lock();
try {
if (tail == head)
throw new EmptyException();
T x = items[head % items.length];
head++;
return x;
} finally {
lock.unlock();
}
}
All modifications
of queue are done
mutually exclusive
Intuitively
Art of Multiprocessor Programming
43
time
q.deq
q.enq
enq
deq
lock()
unlock()
lock()
unlock()
Behavior is “Sequential”
enq
deq
Lets capture the idea of describing
the concurrent via the sequential
Linearizability
Art of Multiprocessor Programming
44
Example
Art of Multiprocessor Programming
45
time
time
(6)
Example
Art of Multiprocessor Programming
46
time
q.enq(x)
time
(6)
Example
Art of Multiprocessor Programming
47
time
q.enq(x)
q.enq(y)
time
(6)
Example
Art of Multiprocessor Programming
48
time
q.enq(x)
q.enq(y)
q.deq(x)
time
(6)
Example
Art of Multiprocessor Programming
49
time
q.enq(x)
q.enq(y)
q.deq(x)
q.deq(y)
time
(6)
Example
Art of Multiprocessor Programming
50
time
q.enq(x)
q.enq(y)
q.deq(x)
q.deq(y)
linearizable
q.enq(x)
q.enq(y)
q.deq(x)
q.deq(y)
time
(6)
Example
Art of Multiprocessor Programming
51
time
q.enq(x)
q.enq(y)
q.deq(x)
q.deq(y)
Valid?
q.enq(x)
q.enq(y)
q.deq(x)
q.deq(y)
time
(6)
Example
Art of Multiprocessor Programming
52
time
(5)
Example
Art of Multiprocessor Programming
53
time
q.enq(x)
(5)
Example
Art of Multiprocessor Programming
54
time
q.enq(x)
q.deq(y)
(5)
Example
Art of Multiprocessor Programming
55
time
q.enq(x)
q.enq(y)
q.deq(y)
(5)
Example
Art of Multiprocessor Programming
56
time
q.enq(x)
q.enq(y)
q.deq(y)
q.enq(x)
q.enq(y)
(5)
Example
Art of Multiprocessor Programming
57
time
q.enq(x)
q.enq(y)
q.deq(y)
q.enq(x)
q.enq(y)
(5)
not linearizable
Example
Art of Multiprocessor Programming
58
time
time
(4)
Example
Art of Multiprocessor Programming
59
time
q.enq(x)
time
(4)
Example
Art of Multiprocessor Programming
60
time
q.enq(x)
q.deq(x)
time
(4)
Example
Art of Multiprocessor Programming
61
time
q.enq(x)
q.deq(x)
q.enq(x)
q.deq(x)
time
(4)
Example
Art of Multiprocessor Programming
62
time
q.enq(x)
q.deq(x)
q.enq(x)
q.deq(x)
linearizable
time
(4)
Example
Art of Multiprocessor Programming
63
time
q.enq(x)
time
(8)
Example
Art of Multiprocessor Programming
64
time
q.enq(x)
q.enq(y)
time
(8)
Example
Art of Multiprocessor Programming
65
time
q.enq(x)
q.enq(y)
q.deq(y)
time
(8)
Example
Art of Multiprocessor Programming
66
time
q.enq(x)
q.enq(y)
q.deq(y)
q.deq(x)
time
(8)
Art of Multiprocessor Programming
67
q.enq(x)
q.enq(y)
q.deq(y)
q.deq(x)
Comme ci
Example
time
Comme ça
multiple orders OK
linearizable
Read/Write Register Example
Art of Multiprocessor Programming
68
time
read(1)
write(0)
write(1)
write(2)
time
read(0)
(4)
Read/Write Register Example
Art of Multiprocessor Programming
69
time
read(1)
write(0)
write(1)
write(2)
time
read(0)
write(1) already happened
(4)
Read/Write Register Example
Art of Multiprocessor Programming
70
time
read(1)
write(0)
write(1)
write(2)
time
read(0)
write(1)
write(1) already happened
(4)
Read/Write Register Example
Art of Multiprocessor Programming
71
time
read(1)
write(0)
write(1)
write(2)
time
read(0)
write(1)
write(1) already happened
(4)
not linearizable
Read/Write Register Example
Art of Multiprocessor Programming
72
time
read(1)
write(0)
write(1)
write(2)
time
read(1)
write(1) already happened
(4)
Read/Write Register Example
Art of Multiprocessor Programming
73
time
read(1)
write(0)
write(1)
write(2)
time
read(1)
write(1)
write(2)
(4)
write(1) already happened
Read/Write Register Example
Art of Multiprocessor Programming
74
time
read(1)
write(0)
write(1)
write(2)
time
read(1)
write(1)
write(2)
not linearizable
(4)
write(1) already happened
Read/Write Register Example
Art of Multiprocessor Programming
75
time
write(0)
write(1)
write(2)
time
read(1)
(4)
Read/Write Register Example
Art of Multiprocessor Programming
76
time
write(0)
write(1)
write(2)
time
read(1)
write(1)
write(2)
(4)
Read/Write Register Example
Art of Multiprocessor Programming
77
time
write(0)
write(1)
write(2)
time
read(1)
write(1)
write(2)
linearizable
(4)
Split Method Calls into Two Events
Art of Multiprocessor Programming
78
Invocation Notation
Art of Multiprocessor Programming
79
A q.enq(x)
Invocation Notation
Art of Multiprocessor Programming
80
A q.enq(x)
thread
Invocation Notation
Art of Multiprocessor Programming
81
A q.enq(x)
thread
method
Invocation Notation
Art of Multiprocessor Programming
82
A q.enq(x)
thread
object
method
Invocation Notation
Art of Multiprocessor Programming
83
A q.enq(x)
thread
object
method
arguments
History - Describing an Execution
Art of Multiprocessor Programming
84
A q.enq(3)
A q:void
A q.enq(5)
B p.enq(4)
B p:void
B q.deq()
B q:3
Sequence of invocations and responses
H =
Definition
Art of Multiprocessor Programming
85
A q.enq(3)
A q:void
Thread names agree
Object names agree
Method call
(1)
Object Projections
Art of Multiprocessor Programming
86
A q.enq(3)
A q:void
B p.enq(4)
B p:void
B q.deq()
B q:3
H =
Object Projections
Art of Multiprocessor Programming
87
A q.enq(3)
A q:void
B p.enq(4)
B p:void
B q.deq()
B q:3
H|q =
Thread Projections
Art of Multiprocessor Programming
88
A q.enq(3)
A q:void
B p.enq(4)
B p:void
B q.deq()
B q:3
H|B =
Sequential Histories
Art of Multiprocessor Programming
89
A q.enq(3)
A q:void
B p.enq(4)
B p:void
B q.deq()
B q:3
A q:enq(5)
(4)
Sequential Histories
Art of Multiprocessor Programming
90
A q.enq(3)
A q:void
B p.enq(4)
B p:void
B q.deq()
B q:3
A q:enq(5)
match
(4)
Sequential Histories
Art of Multiprocessor Programming
91
A q.enq(3)
A q:void
B p.enq(4)
B p:void
B q.deq()
B q:3
A q:enq(5)
match
match
(4)
Sequential Histories
Art of Multiprocessor Programming
92
A q.enq(3)
A q:void
B p.enq(4)
B p:void
B q.deq()
B q:3
A q:enq(5)
match
match
match
(4)
Sequential Histories
Art of Multiprocessor Programming
93
A q.enq(3)
A q:void
B p.enq(4)
B p:void
B q.deq()
B q:3
A q:enq(5)
match
match
match
Final pending invocation OK
(4)
Sequential Histories
Art of Multiprocessor Programming
94
A q.enq(3)
A q:void
B p.enq(4)
B p:void
B q.deq()
B q:3
A q:enq(5)
match
match
match
Final pending invocation OK
(4)
Method calls of different threads do not interleave
Well-Formed Histories
Art of Multiprocessor Programming
95
H=
A q.enq(3)
B p.enq(4)
B p:void
B q.deq()
A q:void
B q:3
Well-Formed Histories
Art of Multiprocessor Programming
96
H=
A q.enq(3)
B p.enq(4)
B p:void
B q.deq()
A q:void
B q:3
H|B=
B p.enq(4)
B p:void
B q.deq()
B q:3
Per-thread projections sequential
Well-Formed Histories
Art of Multiprocessor Programming
97
H=
A q.enq(3)
B p.enq(4)
B p:void
B q.deq()
A q:void
B q:3
H|B=
B p.enq(4)
B p:void
B q.deq()
B q:3
A q.enq(3)
A q:void
H|A=
Per-thread projections sequential
Equivalent Histories
Art of Multiprocessor Programming
98
H=
A q.enq(3)
B p.enq(4)
B p:void
B q.deq()
A q:void
B q:3
Threads see the same thing in both
A q.enq(3)
A q:void
B p.enq(4)
B p:void
B q.deq()
B q:3
G=
H|A = G|A
H|B = G|B
Legal Histories
Art of Multiprocessor Programming
99
Precedence
Art of Multiprocessor Programming
100
A q.enq(3)
B p.enq(4)
B p.void
A q:void
B q.deq()
B q:3
A method call precedes another if response event precedes invocation event
Method call
Method call
(1)
Non-Precedence
Art of Multiprocessor Programming
101
A q.enq(3)
B p.enq(4)
B p.void
B q.deq()
A q:void
B q:3
Some method calls overlap one another
Method call
Method call
(1)
Notation
Art of Multiprocessor Programming
102
m0
m1
Linearizability
Art of Multiprocessor Programming
103
What is 🡺G ⊂ 🡺S�
Art of Multiprocessor Programming
104
time
a
b
time
(8)
🡺G
🡺S
c
🡺G
🡺G = {a🡪c,b🡪c}
🡺S = {a🡪b,a🡪c,b🡪c}
A limitation on the
Choice of S!
Remarks
Art of Multiprocessor Programming
105
Example
Art of Multiprocessor Programming
106
A q.enq(3)
B q.enq(4)
B q:void
B q.deq()
B q:4
B q:enq(6)
time
B.q.enq(4)
A. q.enq(3)
B.q.deq(4)
B. q.enq(6)
Example
Art of Multiprocessor Programming
107
Complete this pending
invocation
time
B.q.enq(4)
B.q.deq(3)
B. q.enq(6)
A q.enq(3)
B q.enq(4)
B q:void
B q.deq()
B q:4
B q:enq(6)
A. q.enq(3)
Example
Art of Multiprocessor Programming
108
Complete this pending
invocation
time
B.q.enq(4)
B.q.deq(4)
B. q.enq(6)
A.q.enq(3)
A q.enq(3)
B q.enq(4)
B q:void
B q.deq()
B q:4
B q:enq(6)
A q:void
Example
Art of Multiprocessor Programming
109
time
B.q.enq(4)
B.q.deq(4)
B. q.enq(6)
A.q.enq(3)
A q.enq(3)
B q.enq(4)
B q:void
B q.deq()
B q:4
B q:enq(6)
A q:void
discard this one
Example
Art of Multiprocessor Programming
110
time
B.q.enq(4)
B.q.deq(4)
A.q.enq(3)
A q.enq(3)
B q.enq(4)
B q:void
B q.deq()
B q:4
A q:void
discard this one
Example
Art of Multiprocessor Programming
111
A q.enq(3)
B q.enq(4)
B q:void
B q.deq()
B q:4
A q:void
time
B.q.enq(4)
B.q.deq(4)
A.q.enq(3)
Example
Art of Multiprocessor Programming
112
A q.enq(3)
B q.enq(4)
B q:void
B q.deq()
B q:4
A q:void
time
B q.enq(4)
B q:void
A q.enq(3)
A q:void
B q.deq()
B q:4
B.q.enq(4)
B.q.deq(4)
A.q.enq(3)
Example
Art of Multiprocessor Programming
113
B.q.enq(4)
B.q.deq(4)
A.q.enq(3)
A q.enq(3)
B q.enq(4)
B q:void
B q.deq()
B q:4
A q:void
time
B q.enq(4)
B q:void
A q.enq(3)
A q:void
B q.deq()
B q:4
Equivalent sequential history
Composability Theorem
Art of Multiprocessor Programming
114
Linearizability: Summary
Art of Multiprocessor Programming
115
Alternative: Sequential Consistency
Art of Multiprocessor Programming
116
Differs from
linearizability
Sequential Consistency
Art of Multiprocessor Programming
117
Example
Art of Multiprocessor Programming
118
time
(5)
Example
Art of Multiprocessor Programming
119
time
q.enq(x)
(5)
Example
Art of Multiprocessor Programming
120
time
q.enq(x)
q.deq(y)
(5)
Example
Art of Multiprocessor Programming
121
time
q.enq(x)
q.enq(y)
q.deq(y)
(5)
Example
Art of Multiprocessor Programming
122
time
q.enq(x)
q.enq(y)
q.deq(y)
q.enq(x)
q.enq(y)
(5)
Example
Art of Multiprocessor Programming
123
time
q.enq(x)
q.enq(y)
q.deq(y)
q.enq(x)
q.enq(y)
(5)
not linearizable
Example
Art of Multiprocessor Programming
124
time
q.enq(x)
q.enq(y)
q.deq(y)
q.enq(x)
q.enq(y)
(5)
Yet Sequentially Consistent
Theorem
Sequential Consistency is not a local property
(and thus we lose composability…)
Art of Multiprocessor Programming
125
FIFO Queue Example
Art of Multiprocessor Programming
126
time
p.enq(x)
p.deq(y)
q.enq(x)
time
FIFO Queue Example
Art of Multiprocessor Programming
127
time
p.enq(x)
p.deq(y)
q.enq(x)
q.enq(y)
q.deq(x)
p.enq(y)
time
FIFO Queue Example
Art of Multiprocessor Programming
128
time
p.enq(x)
p.deq(y)
q.enq(x)
q.enq(y)
q.deq(x)
p.enq(y)
History H
time
H|p Sequentially Consistent
Art of Multiprocessor Programming
129
time
p.enq(x)
p.deq(y)
p.enq(y)
q.enq(x)
q.enq(y)
q.deq(x)
time
H|q Sequentially Consistent
Art of Multiprocessor Programming
130
time
p.enq(x)
p.deq(y)
q.enq(x)
q.enq(y)
q.deq(x)
p.enq(y)
time
Ordering imposed by p
Art of Multiprocessor Programming
131
time
p.enq(x)
p.deq(y)
q.enq(x)
q.enq(y)
q.deq(x)
p.enq(y)
time
Ordering imposed by q
Art of Multiprocessor Programming
132
time
p.enq(x)
p.deq(y)
q.enq(x)
q.enq(y)
q.deq(x)
p.enq(y)
time
Ordering imposed by both
Art of Multiprocessor Programming
133
p.enq(x)
time
q.enq(x)
q.enq(y)
q.deq(x)
time
p.deq(y)
p.enq(y)
Combining orders
Art of Multiprocessor Programming
134
p.enq(x)
time
q.enq(x)
q.enq(y)
q.deq(x)
time
p.deq(y)
p.enq(y)
Quiescent Consistency
135
Quiescent Consistency
136
Quiescent Consistency
Quiescent consistency allows a group of overlapping calls to be re-ordered. They cannot be re-ordered across a “quiet” region.
137
Quiescent Consistency
138
Quiescently Consistent
What is this?
139
What is this?
140
What is this?
141
What is this?
142
What is this?
143
What is this?
144
Is there overlap?
NOTE: Any linearizable execution is also sequentially consistent and quiescently consistent.
145
Real-World Hardware Memory
Art of Multiprocessor Programming
146
Progress Conditions
147
Deadlock-Free
Art of Multiprocessor Programming
148
Starvation-Free
Art of Multiprocessor Programming
149
Lock-Free
Art of Multiprocessor Programming
150
Wait-Free
Art of Multiprocessor Programming
151
Progress Conditions
152
| Blocking | Non-Blocking |
One Thread Makes Progres | Deadlock-Free | Lock-free |
All threads make progress | Starvation-free | Wait-Free |
MyAtomicInt
public class MyAtomicInt {
Lock lock = new ReentrantLock();
volatile int value;
public MyAtomicInt() {}
public MyAtomicInt(int value) { this.value = value; }
public int get() { return value; }
public void set(int value) { this.value = value; }
public int getAndIncrement() {
try {
lock.lock();
return value++;
} finally {
lock.unlock(); } }
153
MyAtomicInt
154
How to know what’s what?
MyAtomicInt ai = new MyAtomicInt(0);
final int N = 10000;
final int N_THREADS = 10;
for (int i = 0; i < N_THREADS; i++) {
new Thread(() -> {
for (int j = 0; j < N; j++) {
ai.incrementAndGet();
}
}).start();
}
while (Thread.activeCount() > 2) { Thread.yield(); }
System.out.println(ai);
155
How to know what’s what?
MyAtomicInt ai = new MyAtomicInt(0);
final int N = 10000;
final int N_THREADS = 10;
for (int i = 0; i < N_THREADS; i++) {
new Thread(() -> {
for (int j = 0; j < N; j++) {
ai.incrementAndGet();
}
}).start();
}
while (Thread.activeCount() > 2) { Thread.yield(); }
System.out.println(ai);
156
Each thread is wait-free
|
|
Single instruction
How to know what’s what?
MyAtomicInt ai = new MyAtomicInt(0);
final int N = 10000;
final int N_THREADS = 10;
for (int i = 0; i < N_THREADS; i++) {
new Thread(() -> {
for (int j = 0; j < N; j++) {
ai.incrementAndGet();
}
}).start();
}
while (Thread.activeCount() > 2) { Thread.yield(); }
System.out.println(ai);
157
Whole code is lock-free
|
|
While loop usually means not wait free
Unfortunately...
package java.util.concurrent.atomic;
public class AtomicInteger extends Number implements java.io.Serializable {
….
public final int getAndIncrement() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return current; } }
158
Art of Multiprocessor Programming
159
�This work is licensed under a Creative Commons Attribution-ShareAlike 2.5 License.