Część 2 Nie wszyscy naraz,
czyli synchronizacja dla opornych
Maciej J. Mrowiński
mrow@if.pw.edu.pl
Wydział Fizyki Politechnika Warszawska
7 grudnia 2018
Pierwszy przykład poglądowy - ucztujący filozofowie
Dzisiejszy Odcinek Sponsoruje...
Szukamy liczb pierwszych
Szukamy liczb pierwszych
Szukamy liczb pierwszych na przedziale [1, 10
10]
1 void p r i m e P r i n t () {
2 int id = T h r e a d I D . get () ;
3 int b loc k = p owe r (10 , 9) ;
4 for(int i = ( id * b loc k ) +1; i <= ( id +1) * blo ck ; ++ i ) {
5 if( i s P r i m e ( i ) )
6 pr int ( i ) ;
7 }
8 }
Ile możemy zyskać?
Ile możemy zyskać?
Prawo Amdahla
S = 1
1 − p +
pnPrawo Amdahla
Prawo Amdahla
Prawo Amdahla
Prawo Amdahla
S = 1
1 −
56+
16= 3
Prawo Amdahla
Dla n = 10 i p = 0.9 mamy
S ≈ 5
Szukamy dalej liczb pierwszych
Szukamy dalej liczb pierwszych
Wracamy do szukania liczb pierwszych
1 C o u n t e r c o u n t e r = new C o u n t e r (1) ;
2
3 void p r i m e P r i n t () {
4 long n u m b e r = 0;
5 long l imi t = p owe r (10 , 10) ;
6 wh ile( n u m b e r < li mit ) {
7 n u m b e r = c o u n t e r . g e t A n d I n c r e m e n t () ;
8 if( i s P r i m e ( i ) )
9 pr int ( i ) ;
10 }
Wracamy do szukania liczb pierwszych
1 p u b l i c cla ss C o u n t e r {
2 p r i v a t e long va lue ;
3
4 p u b l i c C o u n t e r (int i ) {
5 va lue = i ;
6 }
7
8 p u b l i c long g e t A n d I n c r e m e n t () {
9 r e t u r n val ue ++;
10 }
11 }
Wracamy do szukania liczb pierwszych
1 p u b l i c cla ss C o u n t e r {
2 p r i v a t e long va lue ;
3
4 p u b l i c C o u n t e r (int i ) {
5 va lue = i ;
6 }
7
8 p u b l i c long g e t A n d I n c r e m e n t () {
9 long temp = v alu e ;
10 va lue = temp + 1;
11 r e t u r n temp ;
12 }
Blokady (lock) i sekcje krytyczne
Blokady (lock) i sekcje krytyczne
(critical section)
Blokada
1 p u b l i c i n t e r f a c e Lock {
2 p u b l i c void lock () ;
3 p u b l i c void u n l o c k () ;
4 }
Counter z blokadą
1 p u b l i c cla ss C o u n t e r {
2 p r i v a t e long va lue ;
3 p r i v a t e Lock lock ;
4
5 p u b l i c long g e t A n d I n c r e m e n t () {
6 lock . lock () ;
7 try {
8 long temp = v alu e ;
9 va lue = temp + 1;
10 r e t u r n temp ;
11 } f i n a l l y {
12 lock . u n l o c k () ;
13 }
14 }
15 }
Co z tą blokadą?
Co z tą blokadą?
Lock - podejście 001
1 cl ass L o c k O n e i m p l e m e n t s Lock {
2 p r i v a t e b o o l e a n[] flag = new b o o l e a n[2];
3
4 p u b l i c void lock () {
5 int i = T h r e a d I D . get () ;
6 int j = 1 - i ;
7 flag [ i ] = true;
8 wh ile( flag [ j ]) ;
9 }
10
11 p u b l i c void u n l o c k () {
12 int i = T h r e a d I D . get () ;
13 flag [ i ] = f als e;
14 }
15 }
Pożądane cechy blokady
I
wzajemne wykluczanie (mutual exclusion)
I
brak zakleszczeń (deadlock)
I
brak zagłodzenia (starvation)
Lock - podejście 010
1 cl ass L o c k T w o i m p l e m e n t s Lock {
2 p r i v a t e int v i c t i m ;
3
4 p u b l i c void lock () {
5 int i = T h r e a d I D . get () ;
6 v i c t i m = i ;
7 wh ile( v i c t i m == i ) ;
8 }
9
10 p u b l i c void u n l o c k () {}
11 }
Lock - podejście 011 - algorytm Petersona
1 cl ass P e t e r s o n i m p l e m e n t s Lock {
2 p r i v a t e b o o l e a n[] flag = new b o o l e a n[2];
3 p r i v a t e int v i c t i m ;
4
5 p u b l i c void lock () {
6 int i = T h r e a d I D . get () ;
7 int j = 1 - i ;
8 flag [ i ] = true;
9 v i c t i m = i ;
10 wh ile( flag [ j ] && v i c t i m == i ) ;
11 }
12
13 p u b l i c void u n l o c k () {
14 int i = T h r e a d I D . get () ;
15 flag [ i ] = f als e;
16 }
Lock - podejście 100 - Filter Lock
1 cl ass F i l t e r i m p l e m e n t s Lock {
2 int[] l eve l ;
3 int[] v i c t i m ;
4
5 p u b l i c F i l t e r (int n ) {
6 le vel = new int[ n ];
7 v i c t i m = new int[ n ];
8 }
9
10 p u b l i c void lock () {
11 int me = T h r e a d I D . get () ;
12 for(int i = 1; i < n ; i ++) {
13 le vel [ me ] = i ;
14 v i c t i m [ i ] = me ;
15
16 wh ile(( th ere e x i s t s k != me ) ( l eve l [ k ] >= i &&
v i c t i m [ i ] == me ) ) ;
17 }
18 }
19 p u b l i c void u n l o c k () {
20 int me = T h r e a d I D . get () ;
21 le vel [ me ] = 0;
22 }
23 }
Lock - podejście 100 - Filter Lock
l = 0: n wątków l = 1: n-1 wątków l = 2: n-2 wątków
l = n - 2: 2 wątki CS: 1 wątek
Lock - podejście 101 - Bakery Lock
1 cl ass B a k e r y i m p l e m e n t s Lock {
2 b o o l e a n[] flag ;
3 La bel [] la bel;
4
5 p u b l i c B a k e r y (int n ) {
6 flag = new b o o l e a n[ n ];
7 la bel = new La bel [ n ];
8 }
9
10 p u b l i c void lock () {
11 int i = T h r e a d I D . get () ;
12 flag [ i ] = true;
13 la bel[ i ] = max (la bel[0] , ... ,la bel[n -1]) + 1;
14 wh ile (( th ere e x i s t s k != i ) ( flag [ k ] &&
15 (l abe l[ k ] , k ) << (l abe l[ i ] , i ) ) ) ;
16 }
17
18 p u b l i c void u n l o c k () {
19 flag [ T h r e a d I D . get () ] = f als e;
20 }
21 }
Przykład praktyczny
Przykład praktyczny - Singleton i
double-checked locking
Singleton
1 p u b l i c cla ss S i n g l e t o n {
2 p r i v a t e s t a t i c S i n g l e t o n s i n g l e t o n = null;
3
4 p u b l i c s t a t i c s y n c h r o n i z e d S i n g l e t o n g e t I n s t a n c e () {
5 if( s i n g l e t o n == null) {
6 s i n g l e t o n = new S i n g l e t o n () ;
7 }
8 r e t u r n s i n g l e t o n ;
9 }
10 }
Singleton
1 p u b l i c cla ss S i n g l e t o n {
2 p r i v a t e s t a t i c S i n g l e t o n s i n g l e t o n = null;
3
4 p u b l i c s t a t i c S i n g l e t o n g e t I n s t a n c e () {
5 if( s i n g l e t o n == null) {
6 s y n c h r o n i z e d( S i n g l e t o n .c las s) {
7 s i n g l e t o n = new S i n g l e t o n () ;
8 }
9 }
10 r e t u r n s i n g l e t o n ;
11 }
Singleton
1 p u b l i c cla ss S i n g l e t o n {
2 p r i v a t e s t a t i c S i n g l e t o n s i n g l e t o n = null;
3
4 p u b l i c s t a t i c S i n g l e t o n g e t I n s t a n c e () {
5 if( s i n g l e t o n == null) {
6 s y n c h r o n i z e d( S i n g l e t o n .c las s) {
7 if( s i n g l e t o n == null) {
8 s i n g l e t o n = new S i n g l e t o n () ;
9 }
10 }
11 }
12 r e t u r n s i n g l e t o n ;
13 }
14 }
Singleton
1 p u b l i c cla ss S i n g l e t o n {
2 p r i v a t e s t a t i c S i n g l e t o n s i n g l e t o n = null;
3
4 p u b l i c s t a t i c S i n g l e t o n g e t I n s t a n c e () {
5 if( s i n g l e t o n == null) {
6 s y n c h r o n i z e d( S i n g l e t o n .c las s) {
7 if( s i n g l e t o n == null) {
8 mem = a l l o c a t e () ;
9 s i n g l e t o n = mem ;
10 C o n s t r u c t o r S i n g l e t o n ( s i n g l e t o n ) ;
11 }
12 }
13 }
14 r e t u r n s i n g l e t o n ;
15 }
Singleton
1 p u b l i c cla ss S i n g l e t o n {
2 p r i v a t e s t a t i c cl ass S i n g l e t o n W r a p p e r {
3 s t a t i c S i n g l e t o n s i n g l e t o n = new S i n g l e t o n () ;
4 }
5
6 p u b l i c s t a t i c S i n g l e t o n g e t I n s t a n c e () {
7 r e t u r n S i n g l e t o n W r a p p e r . s i n g l e t o n ;
8 }
9 }
Wracamy do blokad
Wracamy do blokad
Klasy Atomic*
Klasy Atomic*
Klasy Atomic*
java.util.concurrent.atomic
I
AtomicBoolean
I
AtomicInteger
I
AtomicReference<T>
I
. . .
Klasy Atomic*
Przykład - AtomicInteger:
I
int getAndSet(int newValue)
I
int addAndGet(int delta)
I
boolean compareAndSet(int expect, int update)
I
int getAndIncrement()
I
int incrementAndGet()
Klasa ThreadLocal<T>
Klasa ThreadLocal<T>
Klasa ThreadLocal<T>
ThreadLocal<T>
I
T get()
I
protected T initialValue()
I
void set(T value)
I static <S> ThreadLocal<S> withInitial(Supplier<? extends S> supplier)
Klasa ThreadLocal<T>
1 p u b l i c cla ss T h r e a d I D {
2 p r i v a t e s t a t i c fi nal A t o m i c I n t e g e r n e x t I D =
3 new A t o m i c I n t e g e r (0) ;
4
5 p r i v a t e s t a t i c fi nal T h r e a d L o c a l < Integer > t h r e a d I D =
6 T h r e a d L o c a l . w i t h I n i t i a l ( n e x t I D :: g e t A n d I n c r e m e n t ) ;
7
8 p u b l i c s t a t i c int get () {
9 r e t u r n t h r e a d I D . get () ;
10 }
Test-And-Set Lock
1 p u b l i c cla ss T A S L o c k i m p l e m e n t s Lock {
2 A t o m i c B o o l e a n sta te = new A t o m i c B o o l e a n (fal se) ;
3
4 p u b l i c void lock () {
5 wh ile( st ate . g e t A n d S e t (true) ) ;
6 }
7
8 p u b l i c void u n l o c k () {
9 st ate . set (fa lse) ;
10 }
11 }
Test-Test-And-Set Lock
1 p u b l i c cla ss T T A S L o c k i m p l e m e n t s Lock {
2 A t o m i c B o o l e a n sta te = new A t o m i c B o o l e a n (fal se) ;
3
4 p u b l i c void lock () {
5 wh ile(true) {
6 wh ile( st ate . get () ) ;
7
8 if(! sta te . g e t A n d S e t (true) )
9 r e t u r n;
10 }
11 }
12
13 p u b l i c void u n l o c k () {
14 st ate . set (fa lse) ;
15 }
Komunikacja
CPU CPU
pamięć pamięć
CPU
Backoff Lock
1 p u b l i c cla ss B a c k o f f {
2 p r i v a t e fi nal int minDelay , m a x D e l a y ;
3 p r i v a t e int li mit ;
4 p r i v a t e fi nal R a n d o m r a n d o m ;
5
6 p u b l i c B a c k o f f (int min , int max ) {
7 m i n D e l a y = min ;
8 m a x D e l a y = max ;
9 li mit = m i n D e l a y ;
10 r a n d o m = new R a n d o m () ;
11 }
12
13 p u b l i c void b a c k o f f () t h r o w s I n t e r r u p t e d E x c e p t i o n {
14 int d ela y = r a n d o m . n e x t I n t ( lim it ) ;
15 li mit = Math . min ( maxDelay , 2 * li mi t ) ;
16 T h r e a d . sle ep ( del ay ) ;
17 }
Backoff Lock
1 p u b l i c cla ss B a c k o f f L o c k i m p l e m e n t s Lock {
2 p r i v a t e A t o m i c B o o l e a n st ate = new A t o m i c B o o l e a n (f als e) ;
3 p r i v a t e s t a t i c fi nal int M I N _ D E L A Y = ...;
4 p r i v a t e s t a t i c fi nal int M A X _ D E L A Y = ...;
5
6 p u b l i c void lock () {
7 B a c k o f f b a c k o f f = new B a c k o f f ( MIN_DELAY , M A X _ D E L A Y ) ;
8 wh ile(true) {
9 wh ile( st ate . get () ) ;
10 if(! sta te . g e t A n d S e t (true) ) {
11 r e t u r n;
12 } else {
13 b a c k o f f . b a c k o f f () ;
14 }
15 }
16 }
17
18 p u b l i c void u n l o c k () {
19 st ate . set (fa lse) ;
20 }
21 }
Blokady z kolejkami
Blokady z kolejkami
Array Lock
1 p u b l i c cla ss ALo ck i m p l e m e n t s Lock {
2 T h r e a d L o c a l < Integer > m y S l o t I n d e x = new T h r e a d L o c a l < >() ; 3
4 A t o m i c I n t e g e r tail ; 5 v o l a t i l e b o o l e a n[] flag ; 6 int c a p a c i t y ;
7
8 p u b l i c ALo ck (int c a p a c i t y ) { 9 this. c a p a c i t y = c a p a c i t y ; 10 tail = new A t o m i c I n t e g e r (0) ; 11 flag = new b o o l e a n[ c a p a c i t y ];
12 flag [0] = true;
13 }
14
15 p u b l i c void lock () {
16 int slot = tail . g e t A n d I n c r e m e n t () % c a p a c i t y ; 17 m y S l o t I n d e x . set ( slot ) ;
18 wh ile(! flag [ slot ]) ;
19 }
20
21 p u b l i c void u n l o c k () {
22 int slot = m y S l o t I n d e x . get () ;
23 flag [ slot ] = f als e;
24 flag [( slot + 1) % c a p a c i t y ] = true;
25 }
26 }
CLH Lock (prawie)
1 p u b l i c cla ss C L H L o c k i m p l e m e n t s Lock { 2 p r i v a t e s t a t i c cl ass QN ode { 3 v o l a t i l e b o o l e a n l o c k e d = fal se;
4 }
5
6 A t o m i c R e f e r e n c e < QNode > tail = new A t o m i c R e f e r e n c e < >(new QNo de () ) ; 7 T h r e a d L o c a l < QNode > m y N o d e = T h r e a d L o c a l . w i t h I n i t i a l ( Q Nod e ::new) ; 8
9 p u b l i c void lock () {
10 QN ode qn ode = m y N o d e . get () ; 11 qn ode . l o c k e d = true;
12 QN ode pred = tail . g e t A n d S e t ( q nod e ) ; 13 wh ile( pred . l o c k e d ) ;
14 }
15
16 p u b l i c void u n l o c k () {
17 QN ode qn ode = m y N o d e . get () ; 18 qn ode . l o c k e d = f als e;
19 }
CLH Lock
1 p u b l i c cla ss C L H L o c k i m p l e m e n t s Lock { 2 p r i v a t e s t a t i c cl ass QN ode { 3 v o l a t i l e b o o l e a n l o c k e d = fal se;
4 }
5
6 A t o m i c R e f e r e n c e < QNode > tail = new A t o m i c R e f e r e n c e < >(new QNo de () ) ; 7 T h r e a d L o c a l < QNode > m y P r e d = new T h r e a d L o c a l < >() ;
8 T h r e a d L o c a l < QNode > m y N o d e = T h r e a d L o c a l . w i t h I n i t i a l ( Q Nod e ::new) ; 9
10 p u b l i c void lock () {
11 QN ode qn ode = m y N o d e . get () ; 12 qn ode . l o c k e d = true;
13 QN ode pred = tail . g e t A n d S e t ( q nod e ) ; 14 m y P r e d . set ( pred ) ;
15 wh ile( pred . l o c k e d ) ;
16 }
17
18 p u b l i c void u n l o c k () {
19 QN ode qn ode = m y N o d e . get () ; 20 qn ode . l o c k e d = f als e;
21 m y N o d e . set ( m y P r e d . get () ) ;
22 }
23 }
MCS Lock (prawie)
1 p u b l i c cla ss M C S L o c k i m p l e m e n t s Lock { 2 p r i v a t e s t a t i c cl ass QN ode { 3 v o l a t i l e b o o l e a n l o c k e d = fal se; 4 v o l a t i l e Q Nod e next = null;
5 }
6
7 A t o m i c R e f e r e n c e < QNode > tail = new A t o m i c R e f e r e n c e < >(null) ; 8 T h r e a d L o c a l < QNode > m y N o d e = T h r e a d L o c a l . w i t h I n i t i a l ( QN ode ::new) ; 9
10 p u b l i c void lock () {
11 QN ode qn ode = m y N o d e . get () ; 12 QN ode pred = tail . g e t A n d S e t ( q nod e ) ;
13 if( pred != null) {
14 qn ode . l o c k e d = true;
15 pred . next = q nod e ;
16 wh ile( qn ode . l o c k e d ) ;
17 }
18 }
19
20 p u b l i c void u n l o c k () { 21 QN ode qn ode = m y N o d e . get () ;
22 if( qno de . next == null)
23 r e t u r n;
24
25 qn ode . next . l o c k e d = f als e;
26 qn ode . next = null;
27 }
MCS Lock
1 p u b l i c cla ss M C S L o c k i m p l e m e n t s Lock { 2 p r i v a t e s t a t i c cl ass QN ode { 3 v o l a t i l e b o o l e a n l o c k e d = fal se; 4 v o l a t i l e Q Nod e next = null;
5 }
6
7 A t o m i c R e f e r e n c e < QNode > tail = new A t o m i c R e f e r e n c e < >(null) ; 8 T h r e a d L o c a l < QNode > m y N o d e = T h r e a d L o c a l . w i t h I n i t i a l ( QN ode ::new) ; 9
10 p u b l i c void lock () {
11 QN ode qn ode = m y N o d e . get () ; 12 QN ode pred = tail . g e t A n d S e t ( q nod e ) ;
13 if( pred != null) {
14 qn ode . l o c k e d = true;
15 pred . next = q nod e ;
16 wh ile( qn ode . l o c k e d ) ;
17 }
18 }
19
20 p u b l i c void u n l o c k () { 21 QN ode qn ode = m y N o d e . get () ;
22 if( qno de . next == null) {
23 if( tail . c o m p a r e A n d S e t ( qnode , null) )
24 r e t u r n;
25 wh ile( qn ode . next == null) ;
26 }
27 qn ode . next . l o c k e d = f als e;
28 qn ode . next = null;
29 }
30 }
Monitor
Monitor
Problem
1 mu tex . lock () ; 2 try {
3 qu eue . enq ( x ) ; 4 } f i n a l l y { 5 mu tex . u n l o c k () ; 6 }
Monitor
java.util.concurrent.locks.Lock
I
void lock()
I
void lockInterruptibly()
I
boolean tryLock()
I
boolean tryLock(long time, TimeUnit unit)
I
void unlock()
I
Condition newCondition()
Condition
java.util.concurrent.locks.Condition
I
void await()
I
boolean await(long time, TimeUnit unit)
I
long awaitNanos(long nanosTimeout)
I
void awaitUninterruptibly()
I
boolean awaitUntil(Date deadline)
I
void signal()
I
void signalAll()
Przykład - BoundedBuffer
1 cl ass B o u n d e d B u f f e r {
2 fi nal Lock lock = new R e e n t r a n t L o c k () ; 3 fi nal C o n d i t i o n n o t F u l l = lock . n e w C o n d i t i o n () ; 4 fi nal C o n d i t i o n n o t E m p t y = lock . n e w C o n d i t i o n () ; 5 fi nal O b j e c t [] it ems = new O b j e c t [ 1 0 0 ] ;
6 int putptr , takeptr , c oun t ;
7
8 p u b l i c void put ( O b j e c t x ) t h r o w s I n t e r r u p t e d E x c e p t i o n {
9 lock . lock () ;
10 try {
11 wh ile( co unt == it ems . l e n g t h ) n o t F u l l . a wai t () ;
12 it ems [ p u t p t r ] = x ;
13 if(++ p u t p t r == ite ms . l e n g t h ) p u t p t r = 0;
14 ++ cou nt ;
15 n o t E m p t y . s i g n a l () ;
16 } f i n a l l y {
17 lock . u n l o c k () ;
18 }
19 }
20 p u b l i c O b j e c t take () t h r o w s I n t e r r u p t e d E x c e p t i o n {
21 lock . lock () ;
22 try {
23 wh ile( co unt == 0) n o t E m p t y . aw ai t () ; 24 O b j e c t x = ite ms [ t a k e p t r ];
25 if(++ t a k e p t r == ite ms . l e n g t h ) t a k e p t r = 0;
26 -- c oun t ;
27 n o t F u l l . s i g n a l () ;
28 r e t u r n x ;
29 } f i n a l l y {
30 lock . u n l o c k () ;
31 }
32 }
Reentrant Lock
Reentrant Lock
Przykład - Reentrant Lock
1 p u b l i c cla ss S i m p l e R e e n t r a n t L o c k i m p l e m e n t s Lock { 2 p r i v a t e fi nal Lock lock = new S i m p l e L o c k () ;
3 p r i v a t e fi nal C o n d i t i o n c o n d i t i o n = lock . n e w C o n d i t i o n () ; 4 p r i v a t e int ow ner = 0;
5 p r i v a t e int h o l d C o u n t = 0;
Przykład - Reentrant Lock
6 p u b l i c void lock () { 7 int me = T h r e a d I D . get () ;
8 lock . lock () ;
9 try {
10 if( own er == me ) {
11 h o l d C o u n t ++;
12 r e t u r n;
13 }
14 wh ile( h o l d C o u n t != 0) c o n d i t i o n . a wai t () ; 15
16 ow ner = me ;
17 h o l d C o u n t = 1;
18 } f i n a l l y {
19 lock . u n l o c k () ;
20 }
21 }
22
23 p u b l i c void u n l o c k () {
24 lock . lock () ;
25 try {
26 if( h o l d C o u n t == 0 || own er != T h r e a d I D . get () ) 27 th row new I l l e g a l M o n i t o r S t a t e E x c e p t i o n () ;
28 holdCount - -;
29 if( h o l d C o u n t == 0)
30 c o n d i t i o n . s i g n a l () ;
31 } f i n a l l y {
32 lock . u n l o c k () ;
33 }
34 }
35 }
Readers–Writers Problem
Readers–Writers Problem
ReadWriteLock
ReadWriteLock
I
Lock readLock()
I
Lock writeLock()
ReadWriteLock
1 p u b l i c cla ss S i m p l e R e a d W r i t e L o c k i m p l e m e n t s R e a d W r i t e L o c k { 2 p r i v a t e int r e a d e r s = 0;
3 p r i v a t e b o o l e a n w r i t e r = fa lse;
4 p r i v a t e fi nal Lock lock = new R e e n t r a n t L o c k () ;
5 p r i v a t e fi nal C o n d i t i o n c o n d i t i o n = lock . n e w C o n d i t i o n () ; 6 p r i v a t e fi nal Lock r e a d L o c k = new R e a d L o c k () ;
7 p r i v a t e fi nal Lock w r i t e L o c k = new W r i t e L o c k () ; 8
9 p u b l i c Lock r e a d L o c k () { 10 r e t u r n r e a d L o c k ;
11 }
12
13 p u b l i c Lock w r i t e L o c k () { 14 r e t u r n w r i t e L o c k ;
ReadWriteLock
16 p r i v a t e cl ass R e a d L o c k i m p l e m e n t s Lock {
17 p u b l i c void lock () {
18 lock . lock () ;
19 try {
20 wh ile( w r i t e r ) c o n d i t i o n . aw ait () ;
21 r e a d e r s ++;
22 } f i n a l l y {
23 lock . u n l o c k () ;
24 }
25 }
26
27 p u b l i c void u n l o c k () {
28 lock . lock () ;
29 try {
30 readers - -;
31 if( r e a d e r s == 0)
32 c o n d i t i o n . s i g n a l A l l () ;
33 } f i n a l l y {
34 lock . u n l o c k () ;
35 }
36 }
37 }
ReadWriteLock
38 p r i v a t e cl ass W r i t e L o c k i m p l e m e n t s Lock {
39 p u b l i c void lock () {
40 lock . lock () ;
41 try {
42 wh ile( r e a d e r s > 0 || w r i t e r ) c o n d i t i o n . a wai t () ;
43 w r i t e r = true;
44 } f i n a l l y {
45 lock . u n l o c k () ;
46 }
47 }
48
49 p u b l i c void u n l o c k () {
50 lock . lock () ;
51 try {
52 w r i t e r = fal se;
53 c o n d i t i o n . s i g n a l A l l () ;
54 } f i n a l l y {
55 lock . u n l o c k () ;
56 }
57 }
58 }
ReadWriteLock
38 p r i v a t e cl ass W r i t e L o c k i m p l e m e n t s Lock {
39 p u b l i c void lock () {
40 lock . lock () ;
41 try {
42 wh ile( w r i t e r ) c o n d i t i o n . aw ait () ; 43
44 w r i t e r = true;
45 wh ile( r e a d e r s > 0) c o n d i t i o n . aw ait () ;
46 } f i n a l l y {
47 lock . u n l o c k () ;
48 }
49 }
50
51 p u b l i c void u n l o c k () {
52 w r i t e r = fal se;
53 c o n d i t i o n . s i g n a l A l l () ;
54 }
55 }
56 }
Przykład praktyczny - listy i zbiory
Przykład praktyczny - listy i zbiory
Set i Node
1 p u b l i c i n t e r f a c e Set < T > { 2 b o o l e a n add ( T x ) ; 3 b o o l e a n r e m o v e ( T x ) ; 4 b o o l e a n c o n t a i n s ( T x ) ; 5 }
6
7 p r i v a t e cl ass Node <T > { 8 v o l a t i l e T item ; 9 v o l a t i l e int key ; 10 v o l a t i l e Node next ; 11 }
Przykład praktyczny - coarse-grained
Lista - coarse-grained
CoarseList
1 p u b l i c cla ss Coa rse Lis t < T > { 2 p r i v a t e Node head ;
3 p r i v a t e Lock lock = new R e e n t r a n t L o c k () ; 4
5 p u b l i c C o a r s e L i s t () {
6 head = new Node ( I n t e g e r . M I N _ V A L U E ) ; 7 head . next = new Node ( I n t e g e r . M A X _ V A L U E ) ;
8 }
9
10 p u b l i c b o o l e a n add ( T item ) {
11 Node pred , curr ;
12 int key = item . h a s h C o d e () ;
13 lock . lock () ;
14 try {
15 pred = head ;
16 curr = pred . next ;
17 wh ile( curr . key < key ) {
18 pred = curr ;
19 curr = curr . next ;
20 }
21 if( key == curr . key ) {
22 r e t u r n fal se;
23 } else {
24 Node node = new Node ( item ) ;
25 node . next = curr ;
26 pred . next = node ;
27 r e t u r n true;
28 }
29 } f i n a l l y {
30 lock . u n l o c k () ;
31 }
32 }
CoarseList
33 p u b l i c b o o l e a n r e m o v e ( T item ) {
34 Node pred , curr ;
35 int key = item . h a s h C o d e () ;
36 lock . lock () ;
37 try {
38 pred = head ;
39 curr = pred . next ;
40 wh ile( curr . key < key ) {
41 pred = curr ;
42 curr = curr . next ;
43 }
44 if( key == curr . key ) {
45 pred . next = curr . next ;
46 r e t u r n true;
47 } else {
48 r e t u r n fal se;
49 }
50 } f i n a l l y {
51 lock . u n l o c k () ;
52 }
53 }
54
55 ...
Przykład praktyczny - fine-grained
Lista - fine-grained
FineList
1 p u b l i c b o o l e a n add ( T item ) { 2 int key = item . h a s h C o d e () ;
3 head . lock () ;
4 Node pred = head ;
5 try {
6 Node curr = pred . next ;
7 curr . lock () ;
8 try {
9 wh ile( curr . key < key ) {
10 pred . u n l o c k () ;
11 pred = curr ;
12 curr = curr . next ;
13 curr . lock () ;
14 }
15 if( curr . key == key ) {
16 r e t u r n fal se;
17 }
18 Node n e w N o d e = new Node ( item ) ;
19 n e w N o d e . next = curr ;
20 pred . next = n e w N o d e ;
21 r e t u r n true;
22 } f i n a l l y {
23 curr . u n l o c k () ;
24 }
25 } f i n a l l y {
26 pred . u n l o c k () ;
27 }
FineList
29 p u b l i c b o o l e a n r e m o v e ( T item ) {
30 Node pred = null, curr = null;
31 int key = item . h a s h C o d e () ;
32 head . lock () ;
33 try {
34 pred = head ;
35 curr = pred . next ;
36 curr . lock () ;
37 try {
38 wh ile( curr . key < key ) {
39 pred . u n l o c k () ;
40 pred = curr ;
41 curr = curr . next ;
42 curr . lock () ;
43 }
44 if( curr . key == key ) {
45 pred . next = curr . next ;
46 r e t u r n true;
47 }
48 r e t u r n fal se;
49 } f i n a l l y {
50 curr . u n l o c k () ;
51 }
52 } f i n a l l y {
53 pred . u n l o c k () ;
54 }
55 }
Przykład praktyczny - optimistic
Lista - optymistyczna
OptimisticList
1 p r i v a t e b o o l e a n v a l i d a t e ( Node pred , Node curr ) {
2 Node node = head ;
3 wh ile( node . key <= pred . key ) {
4 if( node == pred )
5 r e t u r n pred . next == curr ;
6 node = node . next ;
7 }
8 r e t u r n fal se;
9 }
OptimisticList
10 p u b l i c b o o l e a n add ( T item ) { 11 int key = item . h a s h C o d e () ;
12 wh ile(true) {
13 Node pred = head ;
14 Node curr = pred . next ;
15 wh ile( curr . key < key ) {
16 pred = curr ; curr = curr . next ;
17 }
18 pred . lock () ; curr . lock () ;
19 try {
20 if( v a l i d a t e ( pred , curr ) ) {
21 if( curr . key == key ) {
22 r e t u r n fal se;
23 } else {
24 Node node = new Node ( item ) ;
25 node . next = curr ;
26 pred . next = node ;
27 r e t u r n true;
28 }
29 }
30 } f i n a l l y {
31 pred . u n l o c k () ; curr . u n l o c k () ;
32 }
33 }
OptimisticList
35 p u b l i c b o o l e a n r e m o v e ( T item ) { 36 int key = item . h a s h C o d e () ;
37 wh ile(true) {
38 Node pred = head ;
39 Node curr = pred . next ;
40 wh ile( curr . key < key ) {
41 pred = curr ; curr = curr . next ;
42 }
43 pred . lock () ; curr . lock () ;
44 try {
45 if( v a l i d a t e ( pred , curr ) ) {
46 if( curr . key == key ) {
47 pred . next = curr . next ;
48 r e t u r n true;
49 } else {
50 r e t u r n fal se;
51 }
52 }
53 } f i n a l l y {
54 pred . u n l o c k () ; curr . u n l o c k () ;
55 }
56 }
57 }
OptimisticList
58 p u b l i c b o o l e a n c o n t a i n s ( T item ) { 59 int key = item . h a s h C o d e () ;
60 wh ile(true) {
61 Node pred = head ;
62 Node curr = pred . next ;
63 wh ile( curr . key < key ) {
64 pred = curr ; curr = curr . next ;
65 }
66 pred . lock () ; curr . lock () ;
67 try {
68 if( v a l i d a t e ( pred , curr ) ) {
69 r e t u r n( curr . key == key ) ;
70 }
71 } f i n a l l y {
72 pred . u n l o c k () ; curr . u n l o c k () ;
73 }
74 }
Przykład praktyczny - leniwa lista
Lista - leniwa
LazyList
1 p r i v a t e b o o l e a n v a l i d a t e ( Node pred , Node curr ) {
2 r e t u r n ! pred . m a r k e d && ! curr . m a r k e d && pred . next == curr ;
3 }
LazyList
4 p u b l i c b o o l e a n add ( T item ) { 5 int key = item . h a s h C o d e () ;
6 wh ile(true) {
7 Node pred = head ;
8 Node curr = head . next ;
9 wh ile( curr . key < key ) {
10 pred = curr ; curr = curr . next ;
11 }
12 pred . lock () ;
13 try {
14 curr . lock () ;
15 try {
16 if( v a l i d a t e ( pred , curr ) ) {
17 if( curr . key == key ) {
18 r e t u r n fal se;
19 } else {
20 Node node = new Node ( item ) ;
21 node . next = curr ;
22 pred . next = node ;
23 r e t u r n true;
24 }
25 }
26 } f i n a l l y {
27 curr . u n l o c k () ;
28 }
29 } f i n a l l y {
30 pred . u n l o c k () ;
31 }
32 }
33 }
LazyList
34 p u b l i c b o o l e a n r e m o v e ( T item ) { 35 int key = item . h a s h C o d e () ;
36 wh ile(true) {
37 Node pred = head ;
38 Node curr = head . next ;
39 wh ile( curr . key < key ) {
40 pred = curr ; curr = curr . next ;
41 }
42 pred . lock () ;
43 try {
44 curr . lock () ;
45 try {
46 if( v a l i d a t e ( pred , curr ) ) {
47 if( curr . key != key ) {
48 r e t u r n fal se;
49 } else {
50 curr . m a r k e d = true;
51 pred . next = curr . next ;
52 r e t u r n true;
53 }
54 }
55 } f i n a l l y {
56 curr . u n l o c k () ;
57 }
58 } f i n a l l y {
59 pred . u n l o c k () ;
60 }
61 }
LazyList
63 p u b l i c b o o l e a n c o n t a i n s ( T item ) { 64 int key = item . h a s h C o d e () ;
65 Node curr = head ;
66 wh ile( curr . key < key )
67 curr = curr . next ;
68 r e t u r n curr . key == key && ! curr . m a r k e d ;
69 }
Przykład praktyczny - kolejki
Przykład praktyczny - kolejki
Typy kolejek (i nie tylko)
Pojemność:
I
bounded
I
unbounded Metody:
I
total
I
partial
I
synchronous
Przykład praktyczny - BoundedQueue (partial)
Kolejka - BoundedQueue (partial)
BoundedQueue
1 p u b l i c cla ss B o u n d e d Q u e u e < T > { 2 p r i v a t e cl ass Node {
3 p u b l i c T val ue ;
4 p u b l i c v o l a t i l e Node next ; 5
6 p u b l i c Node ( T val ue ) {
7 this. v alu e = v alu e ;
8 }
9 }
10
11 R e e n t r a n t L o c k e n q L o c k = new R e e n t r a n t L o c k () ; 12 C o n d i t i o n n o t F u l l C o n d i t i o n = e n q L o c k . n e w C o n d i t i o n () ; 13 R e e n t r a n t L o c k d e q L o c k = new R e e n t r a n t L o c k () ; 14 C o n d i t i o n n o t E m p t y C o n d i t i o n = d e q L o c k . n e w C o n d i t i o n () ; 15
16 v o l a t i l e Node head = new Node (null) ; 17 v o l a t i l e tail = head ;
18
19 A t o m i c I n t e g e r size = new A t o m i c I n t e g e r (0) ; 20 int c a p a c i t y ;
21
22 p u b l i c B o u n d e d Q u e u e (int c a p a c i t y ) { 23 this. c a p a c i t y = c a p a c i t y ;
24 }
BoundedQueue
25 p u b l i c void enq ( T x ) {
26 b o o l e a n m u s t W a k e D e q u e u e r s = fa lse; 27 e n q L o c k . lock () ;
28 try {
29 wh ile( size . get () == c a p a c i t y ) 30 n o t F u l l C o n d i t i o n . a wai t () ;
31 Node e = new Node ( x ) ;
32 tail . next = e ;
33 tail = e ;
34 if( size . g e t A n d I n c r e m e n t () == 0) 35 m u s t W a k e D e q u e u e r s = true;
36 } f i n a l l y {
37 e n q L o c k . u n l o c k () ;
38 }
39 if( m u s t W a k e D e q u e u e r s ) {
40 d e q L o c k . lock () ;
41 try {
42 n o t E m p t y C o n d i t i o n . s i g n a l A l l () ;
43 } f i n a l l y {
44 d e q L o c k . u n l o c k () ;
45 }
46 }