Człowiek od robienia hmhmm.
https://koziolekweb.pl/001-o-mnie.html
Lawful | Neutral | Chaos | |
---|---|---|---|
|
|||
|
|||
|
Immutability
Atomics
Eventual Consistency
Lock
synchronized
Thread.sleep
Thread.yeld
Single Thread
Possible consistency
Good
Neutral
Evil
class Account {
private int balance = 0;
public synchronized void withdraw() {balance -= 1;}
public synchronized void deposit() {balance += 1;}
//…
}
class Account {
private final Object monitor = new Object();
private int balance = 0;
public void withdraw() {
synchronized (monitor) {
balance -= 1;
}
}
public void deposit() {
synchronized (monitor) {
balance += 1;
}
}
}
synchronized(object){} -> object is monitor
synchronized method() -> synchronized(this){}
synchronized static method() -> synchronized(this.getClass()){}
interface BankService {
void transfer(Account from, Account to, int value);
}
//…
public class SimpleAccount implements Account {
private int balance;
@Override
public void deposit(int depo) {
//…
balance += depo;
}
@Override
public void withdraw(int with) {
//…
balance -= with;
}
}
public void theProblem() {
var bob = new Account("Bob", RUNS);
var alice = new Account("Alice", RUNS);
var aliceToBob = prepare(RUNS,
() -> bankService.transfer(alice, bob, 1));
var bobToAlice = prepare(RUNS,
() -> bankService.transfer(bob, alice, 1));
var aliceThread = new Thread(aliceToBob, "Alice");
var bobThread = new Thread(bobToAlice, "Bob");
aliceThread.start();
bobThread.start();
aliceThread.join();
bobThread.join();
System.out.printf(STR."""
alice = \{alice}
bob = \{bob}""");
}
class MethodSync implements BankService {
public synchronized void transfer(Account from, Account to, int value) {
from.withdraw(value);
to.deposit(value);
}
}
class ArgumentSync implements BankService {
public void transfer(Account from, Account to, int value) {
synchronized (from) {
synchronized (to) {
from.withdraw(value);
to.deposit(value);
}
}
}
}
class OrderedArgumentSync implements BankService {
public void transfer(Account from, Account to, int value, Comparator<Account> comparator) {
final int compare = comparator.compare(from, to);
if (compare > 0) {
synchronized (from) {
synchronized (to) {
from.withdraw(value);
to.deposit(value);
}
}
} else {
synchronized (to) {
synchronized (from) {
from.withdraw(value);
to.deposit(value);
}
}
}
}
}
class GenericOrderedSync {
public <S1, S2, R> R perform(S1 s1, S2 s2, BiFunction<S1, S2, R> todo,
BiFunction<S1, S2, Integer> orderJudge) {
final Integer order = orderJudge.apply(s1, s2);
if (order > 0) {
synchronized (s1) {
synchronized (s2) {
return todo.apply(s1, s2);
}
}
} else {
synchronized (s2) {
synchronized (s1) {
return todo.apply(s1, s2);
}
}
}
}
}
@Target(METHOD)
@Retention(RUNTIME)
@Documented
public @interface ExtendedLock {
}
@Aspect
public class ExtendedLockAspect {
private final ExtendedLockHandler lockHandler = new ExtendedLockHandler();
@Around("@annotation(pl.koziolekweb.extendedlock.ExtendedLock)")
public Object callWithLock(ProceedingJoinPoint tjp) throws Throwable {
var args = tjp.getArgs();
try {
while (!lockHandler.lock(args)) { }
final Object proceed = tjp.proceed();
while (!lockHandler.unlock(args)) {}
return proceed;
} catch (Throwable t) {
while (!lockHandler.unlock(args)) {} throw t;
} finally {
while (!lockHandler.unlock(args)) {}
}
}
}
public boolean lock(Object[] elements) {
if (lock.tryLock()) {
clean();
for (Object element : elements) {
if (lockMap.containsKey(element)
&& (!lockMap.get(element).isSameThread(getCurrentThread()))) {
free();
return false;
}
}
for (Object element : elements) {
if (lockMap.containsKey(element))
lockMap.get(element).inc();
else
lockMap.put(element, new LockCounter(getCurrentThread()));
}
free();
return true;
}
return false;
}
public class StmAccount implements Account {
private Ref balance;
@SneakyThrows
public void deposit(final int depo) {
LockingTransaction.runInTransaction(() -> {
balance.set((Integer) (balance.deref()) + depo);
return true;
});
}
@SneakyThrows
public void withdraw(int with) {
LockingTransaction.runInTransaction(() -> {
balance.set((Integer) (balance.deref()) - with);
return true;
});
}
}
class MethodSync implements BankService {
public void transfer(Account from, Account to, int value) {
from.withdraw(value);
to.deposit(value);
}
}
public class ExternalStmAccount implements Account {
private Ref balance;
@SneakyThrows
public void deposit(final int depo) {
balance.set((Integer) (balance.deref()) + depo);
}
@SneakyThrows
public void withdraw(int with) {
balance.set((Integer) (balance.deref()) - with);
}
}
class StmSync implements BankService {
@SneakyThrows
public void transfer(Account from, Account to, int value) {
LockingTransaction.runInTransaction(() -> {
from.withdraw(value);
to.deposit(value);
return true;
});
}
}
public class PhaserExample {
public static void main(String[] args) {
Phaser phaser = new Phaser(1);
new Thread(new Action("T1", phaser), "T1").start();
new Thread(new Action("T2", phaser), "T2").start();
phaser.arriveAndAwaitAdvance();
new Thread(new Action("T3", phaser), "T3").start();
new Thread(new Action("T4", phaser), "T4").start();
phaser.arriveAndDeregister();
}
}
class Action implements Runnable {
private final String threadName;
private final Phaser phaser;
public void run() {
phaser.arriveAndAwaitAdvance();
try {
System.out.println("start " + threadName);
Thread.sleep(1000);
if (Math.random() > 0.2) {
throw new IllegalStateException("Die!");
}
System.out.println("end " + threadName);
} catch (InterruptedException e) {
e.printStackTrace();
}
phaser.arriveAndDeregister();
}
}
start T2
start T1
end T1
end T2
start T4
start T3
Exception in thread "T4" Exception in thread "T3"
java.lang.IllegalStateException: Die!
at pl.koziolekweb.simple.Action.run(PhaserExample.java:35)
at java.base/java.lang.Thread.run(Thread.java:1583)
java.lang.IllegalStateException: Die!
at pl.koziolekweb.simple.Action.run(PhaserExample.java:35)
at java.base/java.lang.Thread.run(Thread.java:1583)
class SimpleTask implements Callable<Void> {
public Void call() {
System.out.println("start " + threadName);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (Math.random() > 0.2) {
throw new IllegalStateException("Die!");
}
System.out.println("end " + threadName);
return null;
}
}
public class StructuredConcurrenceExample {
public static void main(String[] args) throws InterruptedException,
ExecutionException {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
StructuredTaskScope.Subtask<Void> t1 = scope.fork(new SimpleTask("T1"));
StructuredTaskScope.Subtask<Void> t2 = scope.fork(new SimpleTask("T2"));
scope.join().throwIfFailed();
StructuredTaskScope.Subtask<Void> t3 = scope.fork(new SimpleTask("T3"));
StructuredTaskScope.Subtask<Void> t4 = scope.fork(new SimpleTask("T4"));
scope.join().throwIfFailed();
}
}
}
class Sandbox<T> extends StructuredTaskScope<T> {
@Override
protected void handleComplete(Subtask<? extends T> subtask) {
if (subtask.state() == Subtask.State.FAILED) {
System.out.println(STR."""
end \{((SimpleTask) subtask.task()).getThreadName()}
but \{subtask.exception().getMessage()}""");
}
}
@Override
public Sandbox<T> join() throws InterruptedException {
super.join();
return this;
}
}
public class CustomScopeStructuredConcurrency {
public static void main(String[] args) throws InterruptedException {
try (var scope = new Sandbox<Void>()) {
StructuredTaskScope.Subtask<Void> t1 = scope.fork(new SimpleTask("T1"));
StructuredTaskScope.Subtask<Void> t2 = scope.fork(new SimpleTask("T2"));
scope.join();
StructuredTaskScope.Subtask<Void> t3 = scope.fork(new SimpleTask("T3"));
StructuredTaskScope.Subtask<Void> t4 = scope.fork(new SimpleTask("T4"));
scope.join();
}
}
}
start T2
start T1
end T2
end T1
but Die!
start T3
start T4
end T3
end T4