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 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
| public class TestThreadSafety {
public interface Holder {
public void assertSanity();
}
@NotThreadSafe
public static class MutableHolder implements Holder {
private int n;
public MutableHolder(int n) {
this.n = n;
}
@Override
public void assertSanity() {
if (n != n) {
throw new AssertionError("This statement is false.");
}
}
}
@ThreadSafe
public static class FinalHolder implements Holder {
private final int n;
public FinalHolder(int n) {
this.n = n;
}
@Override
public void assertSanity() {
if (n != n) {
throw new AssertionError("This statement is false.");
}
}
}
@ThreadSafe
public static class SynchronizedSafeHolder implements Holder {
private int n;
public SynchronizedSafeHolder(int n) {
synchronized (this) {
this.n = n;
}
}
@Override
public synchronized void assertSanity() {
if (n != n) {
throw new AssertionError("This statement is false.");
}
}
}
@ThreadSafe
public static class VolatileSafeHolder implements Holder {
private volatile int n; // atomique
public VolatileSafeHolder(int n) {
synchronized (this) {
this.n = n;
}
}
@Override
public synchronized void assertSanity() {
if (n != n) {
throw new AssertionError("This statement is false.");
}
}
}
@ThreadSafe
public static class AtomicSafeHolder implements Holder {
// Le final importe !
private final AtomicInteger n = new AtomicInteger(10);
public AtomicSafeHolder(int n) {
this.n.set(n);
}
@Override
public synchronized void assertSanity() {
if (n.get() != n.get()) {
throw new AssertionError("This statement is false.");
}
}
}
private static class HolderThread implements Runnable {
// Le final importe !
private final Holder holder;
// Holder doit être thread-safe, même s'il est "donné".
public HolderThread(Holder holder) {
this.holder = holder;
}
@Override
public void run() {
holder.assertSanity();
}
}
private static class HolderThread2 implements Runnable {
// Le final importe !
private final SynchronousQueue<Holder> rdv = new SynchronousQueue<Holder>();
// Holder n'a pas besoin d'être thread-safe s'il est "donné".
public HolderThread2(Holder holder) {
rdv.offer(holder);
}
@Override
public void run() {
try {
Holder holder = rdv.take();
holder.assertSanity();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
public void testIt() {
// Code susceptible de lever une AssertionError.
new Thread(new HolderThread(new MutableHolder(10))).start();
// Code correct.
new Thread(new HolderThread(new FinalHolder(10))).start();
new Thread(new HolderThread(new SynchronizedSafeHolder(10))).start();
new Thread(new HolderThread(new VolatileSafeHolder(10))).start();
new Thread(new HolderThread(new AtomicSafeHolder(10))).start();
// Code correct.
new Thread(new HolderThread2(new MutableHolder(10))).start();
}
} |
Partager