-1

Class C:

class C extends Thread
{
    public static int cr;

    C(int n) 
    {
        cr = n;
    }

    public void run()
    {
        go();
    }

    synchronized void go()
    {
        for (int i = 0; i < 10000; i++)
        {
            cr++;
        }
    }
}

Class Launch

class Launch
{
    public static void main(String args[]) throws InterruptedException
    {
        C[] c = new C[10];

        for (int i = 0; i < 10; i++)
        {
            c[i] = new C(0);
        }

        for (int i = 0; i < 10; i++)
        {
            c[i].start();
        }

        System.out.println(C.spaces);
    }
}

It doesn't give me 100,000, but rather numbers below 100k. Why? I made method go() synchronized, so it should be used by only one thread at a time..? What am I missing?

3 Answers3

1

synchronized void go(){...} means that it is synchronized on current instance (on this). Since this method belongs to your custom Thread class and you are crating 10 threads there exist 10 different this references.

That is one of the reasons it is preferred to not extend Thread class, but to implement Runnable interface and pass instance of this interface to as many threads as you want.

Another problem is that you are printing edited value without waiting for threads to finish.

What you need is creating one instance which will hold value you want to change and invoke synchronized method from only one instance, because as mentioned by default synchronized void method is synchronized on this (current object on which this method is invoked).

class MyTask implements Runnable {

    public volatile int counter;

    MyTask(int n) {
        counter = n;
    }

    public void run() {
        System.out.println(Thread.currentThread().getName()+" entered run");
        go();
        System.out.println(Thread.currentThread().getName()+" finished run");
    }

    synchronized void go() {

        System.out.println(Thread.currentThread().getName()+" entered go");
        for (int i = 0; i < 10000; i++) {
            counter++;
        }
        System.out.println(Thread.currentThread().getName()+" left from go");
    }
}

class Luncher {
    public static void main(String args[]) throws InterruptedException {

        //lets create task we want to execute in parallel
        MyTask task = new MyTask(0);

        Thread[] threads = new Thread[10];
        for (int i = 0; i < 10; i++)//create thread instances
            threads[i] = new Thread(task);

        for (int i = 0; i < 10; i++)//start threads
            threads[i].start();

        for (int i = 0; i < 10; i++)
            threads[i].join();//hold main thread to wait till all threads will finish
        System.out.println(task.counter);
    }
}
Pshemo
  • 122,468
  • 25
  • 185
  • 269
  • *It doesn't give me 100,000* because main thread is not waiting for other threads to finish. – Braj May 31 '14 at 14:34
  • @Braj I know. That is another problem I mentioned in answer. – Pshemo May 31 '14 at 14:35
  • @Pshemo Although I am not sure how does it work if we have only one object task... How can we have 10 different threads on the same object? – Ijustwant2learn May 31 '14 at 15:22
  • OK, lets check where you are lost. Do you know that `synchronized void foo(){...}` is effectively the same as `void foo(){ synchronized(this){...} }`? – Pshemo May 31 '14 at 15:26
  • Your `go` method belongs to `C` class (which also extended `Thread`). By doing `C c1 = new C(0)` and `C c2 = new C(0)` you are creating two **different** instances of `C`, correct? – Pshemo May 31 '14 at 15:29
  • Wow, I did not. But why `this` is not the same for all threads then (object is the same), or `this` here is a thread object? Thanks again for helping me. – Ijustwant2learn May 31 '14 at 15:29
  • "or this here is a thread object?" Yes, that is exactly what happens here. `this` refers to current Thread and since you have many threads you are synchronizing each of them on themselves, not on some external but **one** object/lock/monitor which they all have access to. That is why you have no real synchronization in your code. – Pshemo May 31 '14 at 15:32
  • If we are talking about code from my answer then yes. `go` is synchronized on instance of `MyTask` which is shared across all threads (I passed it in their constructors) so before each thread will be able to enter `go` it will have to check state of monitor of passed instance. If one of other threads is already inside `go` then monitor is not free so thread will have to wait. I will edit my answer so you could see it better. – Pshemo May 31 '14 at 15:42
  • @Pshemo Thank you, programming's awesome! – Ijustwant2learn May 31 '14 at 15:52
0

with

 c[i] = new C(0);

you are creating new instance of c every time

with

 synchronized void go()
{
    for (int i = 0; i < 10000; i++)
    {
        cr++;
    }
}

you will always get the number less than 10000 i dont know why you are expecting 100,000

Is it a typo mistake i < 10000 where you should have u used 100,000 ?

To answer your last question

I made method go() synchronized, so it should be used by only one thread at a time..?

if only one thread at a time, you don't need synchronized(multithreading concept).

M Sach
  • 33,416
  • 76
  • 221
  • 314
0

It doesn't give me 100,000, but rather numbers below 100k. Why?

Every thing is working fine but main thread is not waiting for other threads to complete the calculation hence output is random in main thread.

Use Thread#join() so that main thread waits for all the other threads to die before executing the last line of the main thread.

for (int i = 0; i < 10; i++) {
    c[i].start();
    c[i].join(); // Waits for this thread to die
}

System.out.println(C.cr); // output 100000

It's worth reading How do I pause main() until all other threads have died?

Community
  • 1
  • 1
Braj
  • 46,415
  • 5
  • 60
  • 76
  • 1
    Thank you very much. But now I get 100,000 even without synchronized... :( I don't understand anything... edit: sorry, I should have join in another loop. Everything works as I excpected now, thanks again! *edit2:* actually no, if I have join in another loop, it doesn't give me 100k even though go is synchronized :( – Ijustwant2learn May 31 '14 at 14:41
  • synchronized is not the issue. The problem is with the `main` thread that is printing the value before waiting for other threads to finish the calculation. It might help you [How to make the main end last?](http://stackoverflow.com/questions/16618113/how-to-make-the-main-end-last) – Braj May 31 '14 at 14:43
  • I did for (int i = 0; i < 10; i++) { c[i].start(); } for (int i = 0; i < 10; i++) { c[i].join(); }, but it doesn't give me 100k even though go is synchronized. – Ijustwant2learn May 31 '14 at 14:49
  • 1
    @Ijustwant2learn If thread `A` invokes `join` on thread `B` then `A` waits until `B` will finish. In this case main thread runs `c[i].start()` and immediately `c[i].join()` which means before it will iterate to next thread `c[i+1]` and start it, it will wait for `c[i]` to finish so effectively you have no parallelism here because only one thread at a time will work. – Pshemo May 31 '14 at 14:50
  • @Pshemo Look at my comment above, I separated join and start into different loops. – Ijustwant2learn May 31 '14 at 14:59
  • @Ijustwant2learn Look at [my answer](http://stackoverflow.com/a/23971194/1393766). There are two problems in your code (1) you synchronize on different objects which means there is no real synchronization, (2) you didn't wait till threads will finish before you printed edited value. – Pshemo May 31 '14 at 15:01