This question already has answers here:
synchronized block for an Integer object
(3 answers)
Closed 5 years ago.
Why doesn't variable named 'count' finally equal to 20000?
public class Main {
private Integer count = 0;
public void increment() {
synchronized (count) {
count++;
}
}
public static void main(String[] args) {
Main app = new Main();
app.doWork();
}
public void doWork() {
Thread t1 = new Thread(new Runnable() {
#Override
public void run() {
for (int i=0; i<10000; i++) {
increment();
}
}
});
Thread t2 = new Thread(new Runnable() {
#Override
public void run() {
for (int i=0; i<10000; i++) {
increment();
}
}
});
t1.start();
t2.start();
System.out.println(count);
}
It seems that thread loses the variable but when does it happen? The same happens in a case of using AtomicInteger too.
P.S. could you please recommend a good course with exercises for learning multithreading in Java?)
Because start creates a new thread, and when you print the count you aren't sure the thread execution is finished.
t1.start();
t2.start();
System.out.println(count); // Here you don't know if t1 and t2 ended their execution
Join threads to wait for them to complete the task:
t1.start();
t2.start();
t1.join(); // wait for t1 to finish
t2.join(); // wait for t2 to finish
System.out.println(count); // 20000
Note: You'll have to handle InterruptedException on join calls.
You synchronize on count. But your code changes count. Different threads synchronizing on different objects don't guarantee atomicity.
Use a separate final monitor object to synchronize on.
See also #BackSlash 's answer for making sure you print the correct end result.
Edit
His answer comes down to : if you print the result without waiting for the threads to finish on your main thread you'll see some intermediate result, or possibly even 0.
So you need to call join(), which blocks until the thread finishes, on both threads before printing the end result.
Related
Look at this code:
public class VolatileTest {
private static boolean ready = false;
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(){
#Override
public void run() {
ready = true;
System.out.println("t2 thread should stop!");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Thread t2 = new Thread(){
#Override
public void run() {
while(!ready){
System.out.println("invoking..");
}
System.out.println("I was finished");
}
};
t1.start();
t2.start();
}
}
I think the result of this code maybe:
t2 thread should stop!
invoking..
I was finished
because of in the multithreading, when the t1 modify 'ready' variable to true,then I made t1 sleep. At the moment, I think, to t2 the 'ready' variable is false!!! because t1 thread is not stop, the variable in t1 is invisible in t2.
But in fact.. I test many times. the result is always this:
Am my idea is wrong?
First of all, despite calling your class VolatileTest, you are not actually using volatile anywhere in your code.
Since the ready variable is not declared as volatile AND you are accessing it without any explicit synchronization, the behavior is not specified. Specifically, the JLS does not say whether the assignment made in thread 1 to the ready variable will be visible within thread 2.
Indeed, there is not even guaranteed that the run() method for thread 1 will be called before the run() method for thread 2.
Now it seems that your code (as written!) is behaving in a way that is consistent with the write of true always being visible immediately. However, there is no guarantee that that "always" is actually always, or that this will be the case on every Java platform.
I would not be surprised if the syscall associated with sleep is triggering memory cache flushing before the second thread is scheduled. That would be sufficient to cause consistent behavior. Moreover, there is likely to be serendipitous synchronization1 due to the println calls. However, these are not effects you should ever rely on.
1 - Somewhere in the output stream stack for System.out, the println call is likely to synchronize on the stream's shared data structures. Depending on the ordering of the events, this can have the effect of inserting a happens before relationship between the write and read events.
As I mentioned in my comment, there are no guarantees. ("There is no guarantee what value thread t2 will see for ready, because of improper synchronization in your code. It could be true, it could be false. In your case, t2 saw true. That is consistent with "there is no guarantee what value t2 will see")
You can easily get your test to fail by running it multiple times.
When I run below code that does your test 100 times, I always get 14-22 "notReadies", so 14-22% of the cases you will not see the change to ready in Thread t2.
public class NonVolatileTest {
private static boolean ready = false;
private static volatile int notReadies = 0;
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 100; i++) {
ready = false;
// Copy original Thread 1 code from the OP here
Thread t2 = new Thread() {
#Override
public void run() {
if (!ready) {
notReadies++;
}
while (!ready) {
System.out.println("invoking..");
}
System.out.println("I was finished");
}
};
t1.start();
t2.start();
// To reduce total test run time, reduce the sleep in t1 to a
// more suitable value like "100" instead of "5000".
t1.join();
t2.join();
}
System.out.println("Notreadies: " + notReadies);
}
}
public class RunTest {
public static int counter = 0;
static class RunnerDec implements Runnable{
public void run(){
for(int i=0;i<5000; i++){
counter--;
}
}
}
static class RunnerInc implements Runnable{
public void run(){
for(int i=0;i<5000; i++){
counter++;
}
}
}
public static void main(String[] args) {
RunnerDec rd = new RunnerDec();
RunnerInc ri = new RunnerInc();
Thread t1 = new Thread(rd);
Thread t2 = new Thread(ri);
t1.start();
t2.start();
try{
t1.join(); // this will stop the main thread until t1 is done incrementing 5000 times
t2.join(); // this will stop the main thread until t2 is done incrementing 5000 times
}catch(Exception e){
e.printStackTrace();
}
System.out.println(counter);
}
}
I expect the result to be 0 every time alas this is not the case. The java doc says join() "waits for this thread to die". I feel like the main thread should wait for t1 to finish then wait for t2 to finish. That's not what is happening. Thanks for the clarity!!
It does wait for the threads to die. But your two threads concurrently update a shared variable without any synchronization, so you're seeing race conditions and visibility issues.
For example:
counter = 1000
thread 1 reads counter : 1000
thread 2 reads counter : 1000
thread 1 increments and writes counter: 1001
thread 2 decrements and writes counter: 999
Since ++ and -- are not atomic operations, the above thread interlacing example loses an increment.
The easiest way to fix them is to use an AtomicInteger rather than an int. To understand the crux of the problem, you'd better read Java Concurrency in Practice, or at the very least the Java concurrency tutorial.
I would like for thread A to iterate once through the for loop, wait for thread B to loop once through the for loop and wait for thread C to loop once through the for loop. And then all over again. I tried to use wait() and notify() but I got nowhere. How could one solve the problem?
public class Test extends Thread {
static int counter=0;
synchronized public void run() {
for(int i=0; i<4; i++) {
System.out.println(Thread.currentThread().getName()+" "+counter++);
}
}
public static void main(String[] args) throws InterruptedException {
Test t1 = new Test();
Test t2 = new Test();
Test t3 = new Test();
t1.setName("A");
t2.setName("B");
t3.setName("C");
t1.start();
t2.start();
t3.start();
}
}
It should print the following to the console:
A 0
B 1
C 2
A 3
B 4
C 5
A 6
B 7
C 8
A 9
B 10
C 11
But using the code I get a random output like this:
A 0
A 3
A 4
A 5
C 2
C 6
C 7
B 1
C 8
B 9
B 10
B 11
Since you are making instance method syncronized it will try to obtain monitor of current instance and as all 3 threads are different instance all obtain and release monitor independently. You should probably consider using join() to wait for other threads.
You can do something like -
public class Test extends Thread {
static int counter=0;
Test lockTest;
public Test(){}
public Test(Test t) {
this.lockTest = t;
}
public void run() {
for(int i=0; i<4; i++) {
System.out.println(Thread.currentThread().getName()+" "+counter++);
}
if(lockTest != null)
lockTest.join(); //wait for other thread
}
public static void main(String[] args) throws InterruptedException {
Test t1 = new Test(null);
Test t2 = new Test(t1);
Test t3 = new Test(t2);
t1.setName("A");
t2.setName("B");
t3.setName("C");
t1.start();
t2.start();
t3.start();
}
}
If you really need to solve it that way, you can use something like code below. But as other people mentioned it doesn't really make much sense to use threads in such case. I would suggest looking into Future class and ExecutorService.submit if you need to wait for results of computations from various tasks (or even better, guava ListenableFuture). Possibly CyclicBarrier, CountDownLatch, some kind of blocking queue... hard to say without knowing your real usecase, rather than mysterious code question.
public class Test extends Thread {
static int counter=0;
private Test previous;
public void run() {
for(int i=0; i<4; i++) {
synchronized(previous) {
try {
previous.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+" "+counter++);
synchronized(this) {
this.notify();
}
}
}
public static void main(String[] args) throws InterruptedException {
Test t1 = new Test();
Test t2 = new Test();
Test t3 = new Test();
t1.setName("A");
t2.setName("B");
t3.setName("C");
t1.previous = t3;
t2.previous = t1;
t3.previous = t2;
t1.start();
t2.start();
t3.start();
synchronized(t3) {
t3.notify();
}
}
}
If you want to loop endlessly between three Runnables in sequence, create the Runnables and feed them into a single threaded ThreadPoolExecutor or ExecutorService like so:
while (running)
{
ExecutorService threadPool = Executors.newSingleThreadExecutor(Executors.defaultThreadFactory());
threadPool.execute(new RunnableA());
threadPool.execute(new RunnableB());
threadPool.execute(new RunnableC());
threadPool.shutdown();
threadPool.awaitTermination();//put in a try/catch, omitted for brevity
}
That's what you really want. Note that the ExecutorService above has an unbounded queue so you'll have to limit the rate at which you submit tasks or use something like a ThreadPoolExecutor that lets you use bounded queues. Or you could just create a fresh ExecutorService with each loop, call shutdown() after each loop and then await termination at the end of the loop.
In case you were unaware of this, each of the RunnableA/B/C classes above should be soemthing like this:
public class RunnableA implements Runnable()
{
public void run()
{
//do stuff, ie, your loop
}
}
Of course there is always the option to just put all three loops in one method body, which has the advantage of being simpler.
public void doStuff()
{
//loopA
//loopB
//loopC
}
You want a fix type of output i.e. A X, B X, C X, A X, ... . And, you cannot fix the order of an execution of a threads.
And, the actual output you get is based on your syncronized keyword. Which fixes that first A will be printed then B and so on.
You cannot predict the execution of order of threads.
I have this class in which I run a for loop 10 times. This class implements Runnable interface. Now in main() I create 2 threads. Now both will run loop till 10. But I want to check loop count for each thread. If t1 is past 7 then make it sleep 1 second so as to let t2 complete. But how to achieve this? Please see the code. I attempted but looks totally foolish. Just how to check the data of a thread ???
class SimpleJob implements Runnable {
int i;
public void run(){
for(i=0; i<10; i++){
System.out.println(Thread.currentThread().getName()+" Running ");
}
}
public int getCount(){
return i;
}
}
public class Threadings {
public static void main(String [] args){
SimpleJob sj = new SimpleJob();
Thread t1 = new Thread(sj);
Thread t2 = new Thread(sj);
t1.setName("T1");
t2.setName("T2");
t1.start();
try{
if(sj.getCount() > 8){ // I know this looks totally ridiculous, but then how to check variable i being incremented by each thread??
System.out.println("Here");
Thread.sleep(2000);
}
}catch(Exception e){
System.out.println(e);
}
t2.start();
}
}
Please help
You should use some synchronization object, and not rely on slowing down of threads. I strongly suggest you take a look at one of the classes at java.util.concurrent package. You can use for this CountdownLatch - thread 1 will await on it, and thread 2 will perform the countdown and release the lock, and let thread 1 continue (the release should be done at the end of thread 2 code).
I added a synchronized Block, which can be entered by one thread at a time. Both threads call and enter the method parallel. One thread will win the race and take the lock. After the first thread leaves the block it waits 2 seconds. In this time the second thread can iterate over the loop. I think this behaviour is wanted. If the second thread must not wait 2 seconds, too, you can set some boolean flag, that the first thread finished the block and use this flag in an if statement, which prevents the wait time of the second thread.
class SimpleJob implements Runnable {
int i;
public void run(){
synchronized (this) {
for(i=0; i<8; i++){
System.out.println(Thread.currentThread().getName()+" Running ");
}
}
try {
System.out.println("Here");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for(i=0; i<2; i++){
System.out.println(Thread.currentThread().getName()+" Running ");
}
}
public int getCount(){
return i;
}
}
public class Threadings {
public static void main(String [] args){
SimpleJob sj = new SimpleJob();
Thread t1 = new Thread(sj);
Thread t2 = new Thread(sj);
t1.setName("T1");
t2.setName("T2");
t1.start();
t2.start();
}
}
If the goal is to run 2 Runnables in parallel (as Threads) and wait for them both to finish, you can, in increasing order of complexity/power:
Use Thread.join (as suggested by #Suraj Chandran but his reply seems to have been deleted)
Use a CountDownLatch (as also suggested by #zaske)
Use ExecutorService.invokeAll()
EDIT ADDED
First, I don't understand what the magic "if you are at 7 then wait for the other" logic is all about. But, to use Thread.join() from your main code, the code would look like
t1.start(); // Thread 1 starts running...
t2.start(); // Thread 2 starts running...
t1.join(); // wait for Thread 1 to finish
t2.join(); // wait for Thread 2 to finish
// from this point on Thread 1 and Thread 2 are completed...
I'm learning how to work with threads in Java and I need some advice..
I want to print on the standard output numbers from 0..50 with the name of the thread that has done it using three threads.
I have two classes - class Counter that implements Runnable and class Main that creates and runs the threads. Counter has the variable c which is shared among the threads.
My idea was, that I increment c by 1 and then call yield() on the current thread so as the other threads would do the same. Repeat this until c reaches 50.
But it doesen't work, the numbers are printed out in wrong order. How do I fix this?
public class Counter implements Runnable {
Thread t1;
private int c = -1;
public Counter() {
}
public Counter(String name) {
t1 = new Thread(this, name);
t1.start();
}
#Override
public void run() {
while (c < 50) {
increment();
Thread.yield();
}
}
public void increment() {
if (c < 50) {
c++;
System.out.println(Thread.currentThread().getName() + ": " + c);
}
}
}
public class Main {
public static void main(String[] args) throws IllegalThreadStateException {
Counter c1 = new Counter();
Thread t1 = new Thread(c1, "Thread 1");
Thread t2 = new Thread(c1, "Thread 2");
Thread t3 = new Thread(c1, "Thread 3");
t1.start();
t2.start();
t3.start();
}
Edit: In the end I solved it this way. Thank you all who helped me with the tough start with multithreading.
import java.util.concurrent.atomic.AtomicInteger;
public class Counter2 implements Runnable {
// you could also use simple int
private AtomicInteger c = new AtomicInteger(-1);
private static final Object syncObject = new Object();
public Counter2() {
}
#Override
public void run() {
while (c.get() < 50) {
synchronized (syncObject) {
if (c.get() < 50) {
System.out.println(Thread.currentThread().getName() + ": " + c.incrementAndGet());
}
}
}
}
}
Use syncrhonized section in method increment with special static object.
private static final Object syncObj = new Object();
public void increment()
{
syncrhonized( syncObj )
{
c++;
System.out.println(c);
}
}
Or make this method synchronized via its declaration.
But it's wrong idea to store your real data in thread objects. Thread should just to manipulate with share objects but not to store them.\
And actually I don't understand why do you start thread in
Quoting from the javadoc Thread.yield(), emphasis by me:
public static void yield()
A hint to the scheduler that the
current thread is willing to yield its
current use of a processor. The
scheduler is free to ignore this
hint.
...
It is rarely appropriate to use
this method.
Make increment() synchronized in order to prevent other threads from entering the method concurrently.
In conjunction with yield() you should be able to get another thread print the next number (not always since the system might resume the thread that called yield again - see Ingo's answer - , but the order should still be the same).
synchronized increment() would mean that any thread that tries to enter that method on the same object would have to wait if another thread would have aquired the lock already by entering the method.
Yes your code won't work. Thread#yield() won't control the thread scheduler in the manner you desire. I"m curious what result you get. You'll probably get repeated numbers and some number that are slightly out of order.
You could use atomic integer which should remove all duplicates. But since the print statement is not atomic. You may still print your results out of order. So you should probably just synchronize the increment method. Also you don't really need yield so dump it.
If the purpose of the problem is to go from thread 1 to thread 2 to thread 3 back to thread 1, etc... Such that the results are
Thread 1:0
Thread 2:1
Thread 3:2
Thread 1:3
Thread 2:4
Thread 3:5
Thread 1:6
Thread 2:7
....
Then you'll need to lock the increment method and use wait and notifyAll. wait will cause other threads to halt processing until the current thread notifies them to start again.