I encountered this problem when doing a question on LeetCode: https://leetcode.com/problems/print-in-order/
Consider two submissions:
1.
class Foo {
private static int signal = 0;
public Foo() {}
public synchronized void first(Runnable printFirst) throws InterruptedException {
// printFirst.run() outputs "first". Do not change or remove this line.
printFirst.run();
signal += 1;
notifyAll();
}
public synchronized void second(Runnable printSecond) throws InterruptedException {
while(signal != 1)
wait();
// printSecond.run() outputs "second". Do not change or remove this line.
printSecond.run();
signal += 1;
notifyAll();
}
public synchronized void third(Runnable printThird) throws InterruptedException {
while(signal != 2)
wait();
// printThird.run() outputs "third". Do not change or remove this line.
printThird.run();
notifyAll();
}
}
2.
class Foo {
private static int signal = 0;
public Foo() {signal = 0;}
public synchronized void first(Runnable printFirst) throws InterruptedException {
// printFirst.run() outputs "first". Do not change or remove this line.
printFirst.run();
signal += 1;
notifyAll();
}
public synchronized void second(Runnable printSecond) throws InterruptedException {
while(signal != 1)
wait();
// printSecond.run() outputs "second". Do not change or remove this line.
printSecond.run();
signal += 1;
notifyAll();
}
public synchronized void third(Runnable printThird) throws InterruptedException {
while(signal != 2)
wait();
// printThird.run() outputs "third". Do not change or remove this line.
printThird.run();
notifyAll();
}
}
Try submitting these two and you'll find submission 1 will result in Time Limit Exceeded while submission 2 will be accepted.
The only difference is that in submission 2, I explicitly added a statement signal = 0; to initialize the static variable. It should play no difference as I have already given this variable a default value in private static int signal = 0;, so what is going on here. Is there any subtleties in the static field initialization in Java that I did not know?
Thank you very much.
LeetCode runs several different test cases against your solution. Let's assume that LeetCode is running a single JVM and running all the test cases in that JVM, but it is instantiating a new Foo for each case.
When running the first case, signal is zero, and your code works as expected. But at the end of this test case signal is now 2, because the test case increments it twice. Since it is static, it is shared among all instances of Foo. Even though LeetCode instantiates a new Foo for the second test case, the static signal is still 2. The first method increments it to 3, but then the test hangs because the condition while (signal != 1) is always true.
Initializing signal to 0 in the Foo constructor has the effect of resetting signal before the second and subsequent test runs.
There's no reason to make signal static here. It should be a regular non-static member so that each instance of Foo gets a new signal initialized to zero.
Related
I am pretty new to Multithreading programming. In my code threads are trying to acquire locks around few lines. The lines work pretty fine for few context switches but then it halts (probably a deadlock).
On the other hand if use synchronized block then all works fine.
I've four classes.
1. PetersonAlgorithm.java
package com.ashish.master;
public class PetersonAlgorithm {
boolean wantCS[] = {false, false};
int turn = 1;
public void requestCS(int i) {
System.out.println("Lock requested by the thread - " + i);
wantCS[i] = true;
turn = 1 - i;
while(wantCS[1-i] && turn == 1-i);
}
public void releaseCS (int i) {
wantCS[i] = false;
turn = i - 1;
System.out.println("Lock released by the thread - " + i);
}
}
If anyone feels that above algorithm is incorrect then let me know, and feel free to make suggestions.
2. Runner.java
package com.ashish.master;
public class Runner {
public static Incrementer runnableInstance = new Incrementer();
public static Thread inc1 = new Thread(runnableInstance, "0");
public static Thread inc2 = new Thread(runnableInstance, "1");
public static void main(String args[]) {
inc1.start();
inc2.start();
try{
inc1.join();
inc2.join();
} catch (InterruptedException ex) {
System.out.println("The threads have been interrupted while waiting for the join ---> " + ex.getMessage());
}
System.out.println("The total turns taken by incrementer are ----> " + runnableInstance.turns);
}
}
3. Incrementer.java - If synchronized block is used instead of the Peterson algorithm, everything works fine.
package com.ashish.master;
public class Incrementer implements Runnable {
public long turns = 0;
public PetersonAlgorithm pa = new PetersonAlgorithm();
#Override
public void run() {
System.out.println("Thread " + this.toString() + "started.....");
while(true) {
pa.requestCS(Integer.parseInt(this.toString()));
// synchronized(this) {
if(DataStore.data < 1000000) printCriticalSection();
else break;
// }
pa.releaseCS(Integer.parseInt(this.toString()));
}
}
public void printCriticalSection() {
System.out.println("The value of the number is increased by thread " +
this.toString() +" to --> " + DataStore.increase());
turns ++;
}
#Override
public String toString() {
return Thread.currentThread().getName();
}
}
4. DataStore.java A class to mock the data source -- simply increase the number
package com.ashish.master;
public class DataStore {
public static long data = 0L;
public static long increase() {
DataStore.data += 1;
return DataStore.data;
}
}
Your runnables never observe each other's monitors (wantCS and turn) as they have different instances... Each runnable needs to work with a same shared set of monitors!
Take the blue pill and make your PetersonAlgorithm variables static volatile with synchronized block access...
Or take the red pill and you create a Class for your flag monitors (wantCS) and for your indicator monitor (turn). Then just define your runnable with one "own flag", one "observed flag" and one "indicator". Both Runnables will have the same indicator instance (therefore needs to be synchronized) while the flag instances will be crossed (the own flag of R1 will be the observed flag of R2 and the own flag of R2 the observed flag of R1). You should synchronized the flag methods too as you don't want to have a flag raised or lowered while being observed.
Then few steps:
Runnables raise their Flag
Runnables turn the shared Indicator ( set to opponent runnable's id )
Wait if opponent's flag is raised and Indicator is set to opponent.
The non waiting opponent does its stuff then lowers its flag.
The waiting opponent stops waiting (opponent's flag has been lowered), does its stuff and lowers its flag.
Each of your runnable instances has its own PetersonAlgorithm instance. Thus, the two runnables don't know anything about each other and will both always get immediate access to the critical section. Try implementing your PetersonAlgorithm class as static class with static methods. Then change the lines
pa.requestCS(Integer.parseInt(this.toString()));
// ...
pa.releaseCS(Integer.parseInt(this.toString()));
into
PetersonAlgorithm.requestCS(Integer.parseInt(this.toString()));
// ...
PetersonAlgorithm.releaseCS(Integer.parseInt(this.toString()));
I have two threads doing calculation on a common variable "n", one thread increase "n" each time, another decrease "n" each time, when I am not using volatile keyword on this variable, something I cannot understand happens, sb there please help explain, the snippet is like follow:
public class TwoThreads {
private static int n = 0;
private static int called = 0;
public static void main(String[] args) {
for (int i = 0; i < 1000; i++) {
n = 0;
called = 0;
TwoThreads two = new TwoThreads();
Inc inc = two.new Inc();
Dec dec = two.new Dec();
Thread t = new Thread(inc);
t.start();
t = new Thread(dec);
t.start();
while (called != 2) {
//System.out.println("----");
}
System.out.println(n);
}
}
private synchronized void inc() {
n++;
called++;
}
private synchronized void dec() {
n--;
called++;
}
class Inc implements Runnable {
#Override
public void run() {
inc();
}
}
class Dec implements Runnable {
#Override
public void run() {
dec();
}
}
}
1) What I am expecting is "n=0,called=2" after execution, but chances are the main thread can be blocked in the while loop;
2) But when I uncomment this line, the program when as expected:
//System.out.println("----");
3) I know I should use "volatile" on "called", but I cannot explain why the above happens;
4) "called" is "read and load" in working memory of specific thread, but why it's not "store and write" back into main thread after "long" while loop, if it's not, why a simple "print" line can make such a difference
You have synchronized writing of data (in inc and dec), but not reading of data (in main). BOTH should be synchronized to get predictable effects. Otherwise, chances are that main never "sees" the changes done by inc and dec.
You don't know where exactly called++ will be executed, your main thread will continue to born new threads which will make mutual exclusion, I mean only one thread can make called++ in each time because methods are synchronized, and you don't know each exactly thread will be it. May be two times will performed n++ or n--, you don't know this, may be ten times will performed n++ while main thread reach your condition.
and try to read about data race
while (called != 2) {
//System.out.println("----");
}
//.. place for data race, n can be changed
System.out.println(n);
You need to synchronize access to called here:
while (called != 2) {
//System.out.println("----");
}
I sugest to add getCalled method
private synchronized int getCalled() {
return called;
}
and replace called != 2 with getCalled() != 2
If you interested in why this problem occure you can read about visibility in context of java memory model.
This an interview question and i don't think it has any relation with practical real life problems.
I have to print numbers 12345.... sequentially but the condition is i have to print it using two threads one responsible for printing odd numbers and one for even numbers.
till now i have come up with this solution.
package junk.concurrency;
public class PrintEvenOddTester {
public static void main(String... args) {
TaskEvenOdd t = new TaskEvenOdd(10);
Thread t1 = new Thread(t, "odd printer");
Thread t2 = new Thread(t, "even printer");
t1.start();
t2.start();
}
}
class TaskEvenOdd implements Runnable {
private int max;
private boolean isOdd = true;
private int number = 1;
TaskEvenOdd(int max) {
this.max = max;
}
synchronized void printEven(int number) { // sync on runnable itself
while (isOdd) { // if odd is to be printed, wait
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Even:" + this.number); // LINE-1
isOdd = true;
this.number++; // LINE-2
notifyAll();
}
synchronized void printOdd(int number) { // sync on runnable itself
while (!isOdd) { // if even is to be printed, wait
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Odd:" + this.number); // LINE-3
this.number++; // LINE-4
isOdd = false;
notifyAll();
}
#Override
public void run() {
while (number <= max) {
if (Thread.currentThread().getName().equals("even printer")) {
printEven(number);
} else {
printOdd(number);
}
}
}
}
1
while writing this code i observed one strange behaviour which i did not understand. If at LINE-1,2,3,4 in above code, i write number instead of this.number my number instance variable is not getting incremented and code just prints infinite number of 1s.
I assume both the printEven and printOdd method is called on runnable instance itself then why its value is not getting incremented. I tried making number volatile but still it resulted in same output.
2
Also i see numbers are getting printed till 11 not till 10. I understand why this is happening(as the last call to printOdd gets notified by last call of printEven(which is printing 10) thus prints 11 ), one way to avoid this is to check number every time before printing and see if it's under limit but i wanted to know what would be the best way to overcome this.
Thanks.
EDIT method parameter number is completely redundant and can be omitted. This if(this.max>=number) condition can be used before printing the number.
1
Your problem is that the parameter of your method is called number too. So it is shadowing the field of your class! So, when you omit, you inc the parameter; which simply doesn't have any real effect!
There are two solutions to this problem:
a) simply avoid doing it (so, by convention avoid using the same names as parameters and fields).
b) use tooling that spots such problems and tells you about. For example, findbugs has explicit rule to tell you about shadowing. And probably IDE's can be told to warn about this, too. See here.
2
Given the fact that this is just a "simple" assignment ... in my opinion a simple check for the "limit" of the overall class would be just fine.
edit: 1.) Why is "globalCounter" synchronized , but not "Thread.currentThread().getId()"
2.) Can I assign a calculation to each thread? how? Can i work with the results?
public class Hauptprogramm {
public static final int MAX_THREADS = 10;
public static int globalCounter;
public static Integer syncObject = new Integer(0);
public static void main(String[] args) {
ExecutorService threadPool = Executors.newFixedThreadPool(MAX_THREADS);
for (int i = 0; i < MAX_THREADS; i++) {
threadPool.submit(new Runnable() {
public void run() {
synchronized (syncObject) {
globalCounter++;
System.out.println(globalCounter);
System.out.println(Thread.currentThread().getId());
try {
Thread.sleep(10);
} catch (InterruptedException e) {
}
}
}});
}
threadPool.shutdown();
}
}
1.) Why is "globalCounter" synchronized , but not "Thread.currentThread().getId()"
I can answer why globalCounter is synchronized. To avoid data race and race condition.
In case if it is not synchronized - globalCounter++ computation is a three step process (Read-Modify-Write) -
Read the current value of globalCounter varaible.
Modify its value.
Write/ Assign the modified value back to the globalCounter.
In the absence of synchronization in multi threaded environment, there is a possibility that a thread might read/ modifies the value of globalCounter when another thread is in the mid of this 3 step process.
This can result into thread/s reading stale values or loss of update count.
2) Can I assign a calculation to each thread? how? Can i work with the results?
This is possible. You can look into Future/ FutureTask to work with the result
I am taking a book to do some mock test, I have found this question:
import java.util.concurrent.atomic.AtomicInteger;
class AtomicVariableTest {
private static AtomicInteger counter = new AtomicInteger(0);
static class Decrementer extends Thread {
public void run() {
counter.decrementAndGet(); // #1
}
}
static class Incrementer extends Thread {
public void run() {
counter.incrementAndGet(); // #2
}
}
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
new Incrementer().start();
new Decrementer().start();
}
System.out.println(counter);
}
}
The answer:
This program will always print 0.
But I think there is no guarantee that the threads will have completed when it prints the counter value.
I mean, most of the time it will return 0, but if you are strict with the theory there is no guarantee of this.
Am I correct?
There is guaranteed. And there is not guaranteed. There is no middle ground.
In this case there is no guarantee that the result is always zero. This is because the threads are not joined - and might never even have actually ran before the print!
For example, among other permutations, the sequence this code could have executed is:
counter.decrementAndGet(); // #1
System.out.println(counter); // Main thread
counter.incrementAndGet(); // #2
// (and so on, at some arbitrary point after the print)
Avoiding such undesired interleaving/execution is handled in Java (as per the JLS) under happens-before relationships.
If the threads were joined (to the thread with the print) then a happens-before would have been established - in this case that would mean that the threads started and finished running - and the result would be guarantee to be zero.
public static void main(String[] args) {
final List<Thread> threads = new ArrayList<>();
for (int i = 0; i < 5; i++) {
final new Incrementer i = new Incrementer();
threads.add(i);
i.start();
final new Decrementer d = new Decrementer();
threads.add(d);
d.start();
}
for (final Thread t : threads) { t.join(); }
System.out.println(counter);
}
See one of the many duplicates: Wait until child threads completed : Java
And this is why you use the ExecutorService or ExecutorCompletionService and never deal with thread management manually because it is extremely error prone otherwise.