Skip to content

Commit f37ecda

Browse files
rinaldodevrcmoutinho
authored andcommitted
feat(locks): Seção de Locks
Criação da seção sobre Locks com as classes e interfaces do objetivo. Ref. Issue #26
1 parent 2610375 commit f37ecda

File tree

11 files changed

+467
-0
lines changed

11 files changed

+467
-0
lines changed
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
:java-package: src/org/j6toj8/concurrency
2+
:section-java-package: ../../../{java-package}
3+
4+
=== Locks
5+
6+
.Objetivo
7+
--------------------------------------------------
8+
Use Lock, ReadWriteLock, and ReentrantLock classes in the java.util.concurrent.locks and java.util.concurrent.atomic packages to support lock-free thread-safe programming on single variables
9+
-
10+
Usar classes dos tipos Lock, ReadWriteLock, e ReentrantLock dos pacotes java.util.concurrent.locks e java.util.concurrent.atomic para suportar programação sem bloqueio e multi-thread em variáveis únicas
11+
--------------------------------------------------
12+
13+
As classes e interfaces Lock, ReadWriteLock e ReentrantLock permitem obter diferentes tipos de _Locks_ (em tradução livre: bloqueios ou travas). Esses _Locks_ são utilizados para que um número limitado de _threads_ tenham acesso a mesma variável em um determinado momento, ou para que apenas uma delas possa alterar seu valor.
14+
15+
Nesta seção serão apresentados exemplos utilizados essas classes e interfaces. Assim como em outras seções deste capítulo, os exemplos podem ser grandes quando for necessário a criação de __threads__. Dedique um tempo maior para entendê-los completamente.
16+
17+
==== Reentrant Lock
18+
19+
. É possível adquirir um _Lock_ utilizando a classe ``ReentrantLock``.
20+
+
21+
[source,java,indent=0]
22+
.{java-package}/locks/Locks_ReentrantLock.java
23+
----
24+
include::{section-java-package}/locks/Locks_ReentrantLock.java[tag=code]
25+
----
26+
+
27+
.Saída no console
28+
[source,console]
29+
----
30+
ABC
31+
----
32+
+
33+
Perceba que o _lock_ é removido dentro de um bloco ``finally``. Isso garante que uma _thread_ não irá ficar com um _lock_ indeterminadamente.
34+
35+
. Chamar o método unlock sem ter obtido um lock anteriormente irá lançar uma exceção.
36+
+
37+
[source,java,indent=0]
38+
.{java-package}/locks/Locks_UnlockWithoutLock.java
39+
----
40+
include::{section-java-package}/locks/Locks_UnlockWithoutLock.java[tag=code]
41+
----
42+
+
43+
.Saída no console
44+
[source,console]
45+
----
46+
ABC
47+
Exception in thread "main" java.lang.IllegalMonitorStateException
48+
at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:151)
49+
at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1261)
50+
at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:457)
51+
at org.j6toj8.concurrency.locks.Locks_UnlockWithoutLock.main(Locks_UnlockWithoutLock.java:14)
52+
----
53+
54+
. É possível tentar obter um _lock_ imediatamente utilizando o método ``tryLock``.
55+
+
56+
[source,java,indent=0]
57+
.{java-package}/locks/Locks_TryLock.java
58+
----
59+
include::{section-java-package}/locks/Locks_TryLock.java[tag=code]
60+
----
61+
+
62+
.Saída no console
63+
[source,console]
64+
----
65+
ABC
66+
----
67+
68+
. Também é possível tentar obter um _lock_ definindo um tempo de espera máximo.
69+
+
70+
[source,java,indent=0]
71+
.{java-package}/locks/Locks_TryLockTimeout.java
72+
----
73+
include::{section-java-package}/locks/Locks_TryLockTimeout.java[tag=code]
74+
----
75+
+
76+
.Saída no console
77+
[source,console]
78+
----
79+
ABC
80+
----
81+
82+
. Em um cenário com várias __threads__, é possível que apenas uma delas consiga obter um __lock__.
83+
+
84+
[source,java,indent=0]
85+
.{java-package}/locks/Locks_TryLockMultithread.java
86+
----
87+
include::{section-java-package}/locks/Locks_TryLockMultithread.java[tag=code]
88+
----
89+
+
90+
.Saída no console
91+
[source,console]
92+
----
93+
Thread-0: Conseguiu o Lock
94+
Thread-2: Conseguiu o Lock
95+
----
96+
+
97+
Nesta execução com 3 __threads__, apenas duas conseguiram obter o _lock_ imediatamente e imprimir no console. Porém o resultado é imprevisível. Podem existir execuções onde todas obterão o __lock__, e outras em que apenas uma thread conseguirá.
98+
99+
. Uma _thread_ pode obter mais de um _lock_ no mesmo objeto ``Lock``, mas deve desfazer o _lock_ múltiplas vezes também.
100+
+
101+
[source,java,indent=0]
102+
.{java-package}/locks/Locks_LockTwice.java
103+
----
104+
include::{section-java-package}/locks/Locks_LockTwice.java[tag=code]
105+
----
106+
+
107+
.Saída no console
108+
[source,console]
109+
----
110+
ABC
111+
----
112+
+
113+
Como a _thread_ chamou `lock` duas vezes, caso ela não houvesse chamado `unlock` duas vezes, outra _thread_ não seria capaz de obter o __lock__.
114+
115+
. É possível garantir uma distribuição mais "justa" de _locks_ passando `true` como argumento para o ``ReentrantLock``.
116+
+
117+
[source,java,indent=0]
118+
.{java-package}/locks/Locks_Fair.java
119+
----
120+
include::{section-java-package}/locks/Locks_Fair.java[tag=code]
121+
----
122+
+
123+
Ao passar o argumento ``true``, quando várias _threads_ estiverem esperando pelo mesmo __lock__, ele será dado àquela _thread_ que está aguardando a mais tempo.
124+
125+
==== ReentrantReadWriteLock
126+
127+
É possível separar _locks_ de leitura e escrita utilizando a classe ``ReadWriteLock``. _Locks_ de leitura podem ser obtidos por múltiplas __threads__, porém _locks_ de escrita não.
128+
+
129+
[source,java,indent=0]
130+
.{java-package}/locks/Locks_ReadWriteLock.java
131+
----
132+
include::{section-java-package}/locks/Locks_ReadWriteLock.java[tag=code]
133+
----
134+
+
135+
.Saída no console
136+
[source,console]
137+
----
138+
Thread-0: Conseguiu o Lock de leitura
139+
Thread-2: Conseguiu o Lock de leitura
140+
Thread-1: Conseguiu o Lock de leitura
141+
Thread-1: Conseguiu o Lock de escrita
142+
----
143+
+
144+
Perceba que todas as _threads_ conseguiram obter o _lock_ de leitura, porém apenas uma conseguiu obter o _lock_ de escrita.
145+
146+
. Se uma _thread_ já possuir o _lock_ de escrita, outras não conseguirão obter nem mesmo o _lock_ de leitura.
147+
+
148+
[source,java,indent=0]
149+
.{java-package}/locks/Locks_ReadWriteLockInverted.java
150+
----
151+
include::{section-java-package}/locks/Locks_ReadWriteLockInverted.java[tag=code]
152+
----
153+
+
154+
.Saída no console
155+
[source,console]
156+
----
157+
Thread-0: Conseguiu o Lock de escrita
158+
Thread-0: Conseguiu o Lock de leitura
159+
----
160+
+
161+
Perceba que neste exemplo o _lock_ de escrita está sendo obtido *antes* do de leitura, de tal forma que apenas a primeira _thread_ que foi executada conseguiu obter os dois __locks__.
162+
163+
****
164+
165+
* Applying Locks
166+
+
167+
Boyarsky, Jeanne; Selikoff, Scott. OCP: Oracle Certified Professional Java SE 8 Programmer II Study Guide (p. 607). Wiley. Edição do Kindle.
168+
169+
* https://www.baeldung.com/java-concurrent-locks[Guide to java.util.concurrent.Locks.]
170+
171+
* https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/package-summary.html[Package java.util.concurrent.locks.] Java Plataform SE 8.
172+
173+
****

ch06-concurrency.asc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
== Concurrency
33

44
include::book/06-concurrency/sections/01-concurrent-package.asc[]
5+
include::book/06-concurrency/sections/02-locks.asc[]
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package org.j6toj8.concurrency.locks;
2+
3+
import java.util.concurrent.locks.Lock;
4+
import java.util.concurrent.locks.ReentrantLock;
5+
6+
public class Locks_Fair {
7+
8+
public static void main(String[] args) {
9+
// tag::code[]
10+
Lock lock = new ReentrantLock(true); // lock "justo"
11+
try {
12+
lock.lock();
13+
System.out.println("ABC");
14+
} finally {
15+
lock.unlock(); // desfaz o lock
16+
}
17+
// end::code[]
18+
}
19+
20+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package org.j6toj8.concurrency.locks;
2+
3+
import java.util.concurrent.locks.Lock;
4+
import java.util.concurrent.locks.ReentrantLock;
5+
6+
public class Locks_LockTwice {
7+
8+
public static void main(String[] args) {
9+
// tag::code[]
10+
Lock lock = new ReentrantLock();
11+
try {
12+
lock.lock();
13+
lock.lock();
14+
System.out.println("ABC");
15+
} finally {
16+
lock.unlock(); // desfaz o primeiro lock
17+
lock.unlock(); // desfaz o segundo lock
18+
}
19+
// end::code[]
20+
}
21+
22+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package org.j6toj8.concurrency.locks;
2+
3+
import java.util.concurrent.locks.Lock;
4+
import java.util.concurrent.locks.ReadWriteLock;
5+
import java.util.concurrent.locks.ReentrantReadWriteLock;
6+
7+
public class Locks_ReadWriteLock {
8+
9+
// tag::code[]
10+
static class Acao implements Runnable {
11+
12+
private ReadWriteLock lock;
13+
14+
public Acao(ReadWriteLock reentrantLock) {
15+
this.lock = reentrantLock;
16+
}
17+
18+
@Override
19+
public void run() {
20+
Lock readLock = lock.readLock();
21+
if (readLock.tryLock()) {
22+
try {
23+
System.out.println(Thread.currentThread().getName() + ": Conseguiu o Lock de leitura");
24+
} finally {
25+
readLock.unlock();
26+
}
27+
}
28+
29+
Lock writeLock = lock.writeLock();
30+
if (writeLock.tryLock()) {
31+
try {
32+
System.out.println(Thread.currentThread().getName() + ": Conseguiu o Lock de escrita");
33+
} finally {
34+
writeLock.unlock();
35+
}
36+
}
37+
}
38+
}
39+
40+
public static void main(String[] args) {
41+
ReadWriteLock lock = new ReentrantReadWriteLock();
42+
43+
// Criação das threads
44+
Thread thread1 = new Thread(new Acao(lock));
45+
Thread thread2 = new Thread(new Acao(lock));
46+
Thread thread3 = new Thread(new Acao(lock));
47+
48+
// Execução das threads
49+
thread1.start();
50+
thread2.start();
51+
thread3.start();
52+
}
53+
// end::code[]
54+
55+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package org.j6toj8.concurrency.locks;
2+
3+
import java.util.concurrent.locks.Lock;
4+
import java.util.concurrent.locks.ReadWriteLock;
5+
import java.util.concurrent.locks.ReentrantReadWriteLock;
6+
7+
public class Locks_ReadWriteLockInverted {
8+
9+
// tag::code[]
10+
static class Acao implements Runnable {
11+
12+
private ReadWriteLock lock;
13+
14+
public Acao(ReadWriteLock reentrantLock) {
15+
this.lock = reentrantLock;
16+
}
17+
18+
@Override
19+
public void run() {
20+
Lock writeLock = lock.writeLock();
21+
if (writeLock.tryLock()) {
22+
try {
23+
System.out.println(Thread.currentThread().getName() + ": Conseguiu o Lock de escrita");
24+
} finally {
25+
writeLock.unlock();
26+
}
27+
}
28+
29+
Lock readLock = lock.readLock();
30+
if (readLock.tryLock()) {
31+
try {
32+
System.out.println(Thread.currentThread().getName() + ": Conseguiu o Lock de leitura");
33+
} finally {
34+
readLock.unlock();
35+
}
36+
}
37+
}
38+
}
39+
40+
public static void main(String[] args) {
41+
ReadWriteLock lock = new ReentrantReadWriteLock();
42+
43+
// Criação das threads
44+
Thread thread1 = new Thread(new Acao(lock));
45+
Thread thread2 = new Thread(new Acao(lock));
46+
Thread thread3 = new Thread(new Acao(lock));
47+
48+
// Execução das threads
49+
thread1.start();
50+
thread2.start();
51+
thread3.start();
52+
}
53+
// end::code[]
54+
55+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package org.j6toj8.concurrency.locks;
2+
3+
import java.util.concurrent.locks.Lock;
4+
import java.util.concurrent.locks.ReentrantLock;
5+
6+
public class Locks_ReentrantLock {
7+
8+
public static void main(String[] args) {
9+
// tag::code[]
10+
Lock lock = new ReentrantLock();
11+
try {
12+
lock.lock(); // apenas uma thread obtém o lock por vez
13+
System.out.println("ABC");
14+
} finally {
15+
lock.unlock(); // desfaz o lock
16+
}
17+
// end::code[]
18+
}
19+
20+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package org.j6toj8.concurrency.locks;
2+
3+
import java.util.concurrent.locks.Lock;
4+
import java.util.concurrent.locks.ReentrantLock;
5+
6+
public class Locks_TryLock {
7+
8+
public static void main(String[] args) {
9+
// tag::code[]
10+
Lock lock = new ReentrantLock();
11+
boolean temLock = lock.tryLock();
12+
13+
if (temLock) {
14+
try {
15+
System.out.println("ABC");
16+
} finally {
17+
lock.unlock(); // desfaz o lock
18+
}
19+
} else {
20+
System.out.println("DEF");
21+
}
22+
// end::code[]
23+
}
24+
25+
}

0 commit comments

Comments
 (0)