I've implemented the resource hierarchy solution to the Dining Philosopher's Problem. When I try to compare the two Chopsticks' n values, they end up in deadlock. However, if I use their hashCodes instead of n values, it runs smoothly. Why this difference? Aren't they both numbers at the end of the day?
import java.util.Random;
class Chopstick {
public final int n;
public Chopstick(int n) {
this.n = n;
}
}
class Philosopher extends Thread {
private Chopstick left, right;
private Random random;
private final int n;
public Philosopher(int n, Chopstick left, Chopstick right) {
this.n = n;
if (left.n > right.n) { // no deadlock if I replace this with left.hashCode() > right.hashCode()
this.right = left;
this.left = right;
} else {
this.left = left;
this.right = right;
}
this.random = new Random();
}
#Override
public void run() {
try {
while (true) {
Thread.sleep(random.nextInt(10)); // Think
synchronized(left) {
synchronized(right) {
System.out.println("P " + n + " eating");
Thread.sleep(random.nextInt(10));
}
}
}
} catch(InterruptedException ie) {
ie.printStackTrace();
}
}
}
class Main {
public static void main(String[] args) {
final int n = 3;
Chopstick[] sticks = new Chopstick[n];
Philosopher[] ps = new Philosopher[n];
for (int i = 0; i < n; i++) {
sticks[i] = new Chopstick(n);
}
for (int i = 0; i < n; i++) {
ps[i] = new Philosopher(i, sticks[i], sticks[(i + 1) % n]);
ps[i].start();
}
}
}
Your problem is related to the fact that you don't manage cases where left.n == right.n and unfortunately instead of initializing your Chopstick array with sticks[i] = new Chopstick(i), you used sticks[i] = new Chopstick(n) such that you have only cases of type left.n == right.n which are not properly managed so you get deadlocks.
As you did not override the method hashCode(), using hashCode() helps to avoid the problem because they are different instances of Chopstick with different values of hashCode() but you could still meet cases where we have 2 different instances of Chopstick with the same hashCode(). So you still have to manage cases where we have equal values.
The way to manage equal values properly is by using a third lock called the "tie breaking" lock
class Philosopher extends Thread {
// The tie breaking lock
private static Object tieLock = new Object();
...
private void printAndSleep() throws InterruptedException {
synchronized(left) {
synchronized(right) {
System.out.println("P " + n + " eating");
Thread.sleep(random.nextInt(10));
}
}
}
public void run() {
...
if (left.n == right.n) {
// Equal values so we need first to acquire the tie breaking lock
synchronized (tieLock) {
printAndSleep();
}
} else {
printAndSleep();
}
...
}
}
A more generic way to manage lock ordering is by relying on System.identityHashCode(obj) as value of each instance to sort instead of using a field's value or hashCode() because this way you won't depend on something specific to the target object's type.
More details in chapter 10.1.2 Dynamic lock order deadlock of Java Concurrency in Practice from Brian Goetz
The BUG is that you have
sticks[i] = new Chopstick(n);
when it should be
sticks[i] = new Chopstick(i);
The hash values of the objects will still be unique even if their data is the same since you haven't overridden the hashCode function.
Related
I'm trying to stimulate the scenario of deadlocks in the shared array using Reentrant Locks.
class SharedArray {
private int ff[];
private Lock keys[];
public SharedArray(int n){
ff = new int[n];
keys = new ReentrantLock[n];
for(int j = 0; j < n; j++){
ff[j] = (int)(Math.random()*100);
keys[j] = new ReentrantLock();
}
}
void swap(int j, int k) {
keys[j].lock(); keys[k].lock();
int t = ff[j]; ff[j] = ff[k]; ff[k] = t;
keys[j].unlock(); keys[k].unlock();
}
}
Here the swap method is deadlock prone which I have achieved. for example if Thread 1 is swap(7,4) and at the same time Thread 2 is swap(4,7) this will raised the deadlock.
How do I prevent it from deadlock. What sort of refactoring is required. I have tried to used synchronized but I'm looking for possibly a reliable way to solve that.
synchronized void swap(int j, int k) {
keys[j].lock(); keys[k].lock();
int t = ff[j]; ff[j] = ff[k]; ff[k] = t;
keys[j].unlock(); keys[k].unlock();
}
How do I prevent it from deadlock?
One way to prevent deadlock would be to ensure that any threads that acquire the same two locks always will acquire them in the same order.
void swap(int j, int k) {
int first = Math.min(j, k);
int second = Math.max(j, k);
keys[first].lock(); keys[second].lock();
int t = ff[j]; ff[j] = ff[k]; ff[k] = t;
keys[second].unlock(); keys[first].unlock();
}
You want to employ lock ordering. If you lock each time in a predictable order you can prevent dead locking.
Found in Java Concurrency In Practice, you can see an example of how to achieve this:
public void transferMoney(final Account fromAcct, final Account toAcct, final DollarAmount amount)
throws InsufficientFundsException {
class Helper {
public void transfer() throws InsufficientFundsException {
if (fromAcct.getBalance().compareTo(amount) < 0)
throw new InsufficientFundsException();
else {
fromAcct.debit(amount);
toAcct.credit(amount);
}
}
}
int fromHash = System.identityHashCode(fromAcct);
int toHash = System.identityHashCode(toAcct);
if (fromHash < toHash) {
synchronized (fromAcct) {
synchronized (toAcct) {
new Helper().transfer();
}
}
} else if (fromHash > toHash) {
synchronized (toAcct) {
synchronized (fromAcct) {
new Helper().transfer();
}
}
} else {
synchronized (tieLock) {
synchronized (fromAcct) {
synchronized (toAcct) {
new Helper().transfer();
}
}
}
}
}
https://pdfs.semanticscholar.org/3650/4bc31d3b2c5c00e5bfee28ffc5d403cc8edd.pdf, search for Listing 10.3. Inducing a Lock Ordering to Avoid Deadlock.
I've read a lot about thread-safety. In certain part of my multi-threaded program, I preferred to try the immutability. After getting incorrect results, I noticed my immutable object is not thread-safe although it is 100% immutable. Please correct me if I'm wrong.
public final class ImmutableGaugeV4 {
private final long max, current;
public ImmutableGaugeV4(final long max) {
this(max, 0);
}
private ImmutableGaugeV4(final long max, final long current) {
this.max = max;
this.current = current;
}
public final ImmutableGaugeV4 increase(final long increment) {
final long c = current;
return new ImmutableGaugeV4(max, c + increment);
}
public final long getCurrent() {
return current;
}
public final long getPerc() {
return current * 100 / max;
}
#Override
public final String toString() {
return "ImmutableGaugeV4 [max=" + max + ", current=" + current + "](" + getPerc() + "%)";
}
}
aaaaa
public class T4 {
public static void main(String[] args) {
new T4().x();
}
ImmutableGaugeV4 g3 = new ImmutableGaugeV4(10000);
private void x() {
for (int i = 0; i < 10; i++) {
new Thread() {
public void run() {
for (int j = 0; j < 1000; j++) {
g3 = g3.increase(1);
System.out.println(g3);
}
}
}.start();
}
}
}
Sometimes I'm getting correct results, and most of the times I'm not
ImmutableGaugeV4 [max=10000, current=9994](99%)
ImmutableGaugeV4 [max=10000, current=9995](99%)
ImmutableGaugeV4 [max=10000, current=9996](99%)
ImmutableGaugeV4 [max=10000, current=9997](99%)
What is wrong with this immutable object? What is missing to make it thread-safe without using intrinsic locks?
Neither
final long c = current;
return new ImmutableGaugeV4(max, c + increment);
nor
g3 = g3.increase(1);
is thread-safe. These compound actions aren't atomic.
I recommend reading "Java concurrency in practice" by Brian Goetz: the chapters devoted to compound actions and "publication and escape" problems.
Your problem is that you are not using thread safe operations for your numeric variables max and current. Because of that, many threads can get the same value from them even tough it has already been changed.
You could add synchronized blocks to handle reading / writing to them, but the best approach is to use thread safe classes to handle that for you.
If you need long values, that would be AtomicLong. Take a look at it’s documentation, it has methods to do the operations you want.
https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicLong.html
Whenever you’re multithreading you should go for threadsafe objects, such as the Atomic family, ConcurrentHashMap for maps, and so on.
Hope it helps!
The only problem here is the following line:
g3 = g3.increase(1);
This is equivalent to the following lines:
var tmp = g3;
tmp = tmp.increase(1);
g3 = tmp;
To fix this, you could use a Compare And Swap:
private static final VarHandle G3;
static {
try {
G3 = MethodHandles.lookup().findVarHandle(T4.class, "g3", ImmutableGaugeV4.class);
} catch (ReflectiveOperationException roe) {
throw new Error(roe);
}
}
And then replace g3 = g3.increase(1); with:
ImmutableGaugeV4 oldVal, newVal;
do {
oldVal = g3;
newVal = oldVal.increase(1);
} while (!G3.compareAndSet(T4.this, oldVal, newVal));
System.out.println(newVal);
In the end, your T4 becomes:
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
public class T4 {
public static void main(String[] args) {
new T4().x();
}
ImmutableGaugeV4 g3 = new ImmutableGaugeV4(10000);
private static final VarHandle G3;
static {
try {
G3 = MethodHandles.lookup().findVarHandle(T4.class, "g3", ImmutableGaugeV4.class);
} catch (ReflectiveOperationException roe) {
throw new Error(roe);
}
}
private void x() {
for (int i = 0; i < 10; i++) {
new Thread() {
public void run() {
for (int j = 0; j < 1000; j++) {
ImmutableGaugeV4 oldVal, newVal;
do {
oldVal = g3;
newVal = oldVal.increase(1);
} while (!G3.compareAndSet(T4.this, oldVal, newVal));
System.out.println(newVal);
}
}
}.start();
}
}
}
I read now Thinking in Java, chapter about atomicity and visibility. There is an example I don't understand.
public class SerialNumberGenerator {
private static volatile int serialNumber = 0;
public static int nextSerialNumber() {
return serialNumber++;
}
}
class CircularSet {
private int[] array;
private int len;
private int index = 0;
public CircularSet(int size) {
array = new int[size];
len = size;
for (int i = 0; i < size; i++) {
array[i] = -1;
}
}
synchronized void add(int i) {
array[index] = i;
index = ++index % len;
}
synchronized boolean contains(int val) {
for (int i = 0; i < len; i++) {
if (array[i] == val)
return true;
}
return false;
}
}
public class SerialNumberChecker {
private static final int SIZE = 10;
private static CircularSet serials = new CircularSet(1000);
private static ExecutorService exec = Executors.newCachedThreadPool();
static class SerialChecker implements Runnable {
#Override
public void run() {
while (true) {
int serial = SerialNumberGenerator.nextSerialNumber();
if (serials.contains(serial)) {
System.out.println("Duplicate: " + serial);
System.exit(0);
}
serials.add(serial);
}
}
}
public static void main(String[] args) throws Exception {
for (int i = 0; i < SIZE; i++) {
exec.execute(new SerialChecker());
}
}
}
example output:
Duplicate: 228
I don't understand how is it possible. Even method nextSerialNumber() is not synchronized and all thread generate different values each thread has own value of serial and each are different. So how is it possible to find duplicate. I cannot imagine of threads execution.
This example shows the post-increment operator is not atomic and not thread-safe.
What happens in this code is:
many (up to 100) threads are started, each executing the same code
in an infinite loop:
an unsynchronized method nextSerialNumber is called, which returns the result of the post-increment operator called on a static variable
a synchronized method contains is called, which checks if the returned value exists in the underlying collection
if yes, the program is terminated
if not, the value is added to the underlying collection
If the post-increment operation was thread-safe then the program would never print "Duplicate" and would never terminate,
since every thread would be getting a different serial number value. This is not the case as two threads
might get exactly the same serial number value.
I am wondering why the result is not 400 000. There are two threads why does it gets blocked?
class IntCell {
private int n = 0;
public int getN() {return n;}
public void setN(int n) {this.n = n;}
}
class Count extends Thread {
private static IntCell n = new IntCell();
#Override public void run() {
int temp;
for (int i = 0; i < 200000; i++) {
temp = n.getN();
n.setN(temp + 1);
}
}
public static void main(String[] args) {
Count p = new Count();
Count q = new Count();
p.start();
q.start();
try { p.join(); q.join(); }
catch (InterruptedException e) { }
System.out.println("The value of n is " + n.getN());
}
}
Why there is so problem with that?
Because the way you increment your variable is not an atomic operation indeed to increment it you:
Get the previous value
Add one to this value
Set a new value
They are 3 operations not done atomically you should either us a synchronized block or use an AtomicInteger instead.
With a synchronized block it would be something like:
synchronized (n) {
temp = n.getN();
n.setN(temp + 1);
}
With an AtomicInteger you will need to rewrite your code as next:
class IntCell {
private final AtomicInteger n = new AtomicInteger();
public int getN() {return n.get();}
public void incrementN(int n) {this.n.addAndGet(n);}
}
for (int i = 0; i < 200000; i++) {
n.incrementN(1);
}
The approach with an AtomicInteger is non blocking so it will be faster
When two threads access one object at the same time, they interfere with each other, and the result is not deterministic. For example, imagine that p reads the value of n and gets, say, 0, then q reads the same value and gets 0 too, then p sets value to 1 and q also sets it to 1 (because it still thinks that it has value 0). Now the value of n is increased by 1, even though both counters "incremented" it once. You need to use synchronized block to make sure the counters won't interfere with each other. See https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html for more.
The problem here is that you allow for race conditions. Consider the block inside the loop:
temp = n.getN();
n.setN(temp + 1);
The code context switch between the time you get the current N and by the time you increment it, making you set an "old" value. One way around this is to ensure the inner part of the loop runs in a synchronized block:
for (int i = 0; i < 200000; i++) {
synchronized (n) { / Here!
temp = n.getN();
n.setN(temp + 1);
}
}
I am reading "Java Concurrency in practice" and looking at the example code on page 51.
This states that if a thread has references to a shared object then other threads may be able to access that object before the constructor has finished executing.
I have tried to put this into practice and so I wrote this code thinking that if I ran it enough times a RuntimeException("World is f*cked") would occur. But it isn't doing.
Is this a case of the Java spec not guaranting something but my particular implementation of java guaranteeing it for me? (java version: 1.5.0 on Ubuntu) Or have I misread something in the book?
Code: (I expect an exception but it is never thrown)
public class Threads {
private Widgit w;
public static void main(String[] s) throws Exception {
while(true){
Threads t = new Threads();
t.runThreads();
}
}
private void runThreads() throws Exception{
new Checker().start();
w = new Widgit((int)(Math.random() * 100) + 1);
}
private class Checker extends Thread{
private static final int LOOP_TIMES = 1000;
public void run() {
int count = 0;
for(int i = 0; i < LOOP_TIMES; i++){
try {
w.checkMe();
count++;
} catch(NullPointerException npe){
//ignore
}
}
System.out.println("checked: "+count+" times out of "+LOOP_TIMES);
}
}
private static class Widgit{
private int n;
private int n2;
Widgit(int n) throws InterruptedException{
this.n = n;
Thread.sleep(2);
this.n2 = n;
}
void checkMe(){
if (n != n2) {
throw new RuntimeException("World is f*cked");
}
}
}
}
You don't publish the reference until after the constructor has finished, change Widgit like this:
private class Widgit{ // NOTE: Not class is not static anymore
private int n;
private int n2;
Widgit(int n) throws InterruptedException{
this.n = n;
w = this; // publish reference
Thread.sleep(2);
this.n2 = n;
}
void checkMe(){
if (n != n2) {
throw new RuntimeException("World is f*cked");
}
}
Should now throw.
Edit: You should also declare the Widgit field as volatile:
private volatile Widgit w;
Well, you need to understand the issues a little more. It isn't really a case of anything being or not being "guaranteed." With concurrency problems, nothing is really guaranteed unless you really do specific things to force the problem to happen. You're just relying on the hope that enough runs should produce, which is not the case. These kinds of problems are hard to predict, which is why concurrency is a hard problem. You could try doing more work in your functions, but I assure you these are real problems that the runtime is not going to save you from.
Before sleeping, start a new thread which prints the value of n2. You will see the second thread can access the object before the constructor has finished.
The following example demonstrates this on the Sun JVM.
/* The following prints
Incomplete initialisation of A{n=1, n2=0}
After initialisation A{n=1, n2=2}
*/
public class A {
final int n;
final int n2;
public A() throws InterruptedException {
n = 1;
new Thread(new Runnable() {
public void run() {
System.out.println("Incomplete initialisation of " + A.this);
}
}).start();
Thread.sleep(200);
this.n2 = 2;
}
#Override
public String toString() {
return "A{" + "n=" + n + ", n2=" + n2 + '}';
}
public static void main(String... args) throws InterruptedException {
System.out.println("After initialisation " + new A());
}
}
This will never throw a RunTimeException because your Widgit instance variable w remains null until the constructor code has executed. While your main thread is sleeping in the Widgit constructor, your Checker instance is hitting NullPointerException constantly as the w variable is still null. When your main thread finishes construction, the two int variables in Widgit are equal.