3

Following code found that output results is not the order, not from small to large, how to guarantee it is order from small to large?

java code

public class TestSync {  

    /** 
     * @param args 
     */  
    public static void main(String[] args) {  
        for (int i = 0; i < 10; i++) {  
            new Thread(new Thread1()).start();  
        }  

    }  

    public int getNum(int i) {  
        synchronized (this) {  
            i++;  
        }  
        return i;  
    }  

    static class Thread1 implements Runnable {  
        static Integer value = 0;  
        @Override  
        public void run() {  
            TestSync ts = new TestSync();  
            value = ts.getNum(value);  
            System.out.println("thread1:" + value);  
        }  
    }  

}  
3
  • if u want sequential order why use threading? threading is asynchronous. u can store your values in vector which is thread safe and sort after everything is done then print it out Commented Aug 28, 2012 at 3:59
  • You can use java Thread pool or ExecutorService Commented Aug 28, 2012 at 4:02
  • @Nick getNum is just returning 1 for each thread... you never actually modify value. Besides, what you really want is AtomicInteger with its incrementAndGet method. Commented Aug 28, 2012 at 4:12

6 Answers 6

2

What are you trying to accomplish? Your code is only synchronizing calls made to a particular TestSync instance. Since each thread creates its own instance, it's like you are not synchronizing anything at all. Your code is not doing anything to synchronize or coordinate accesses across the different threads.

I'd suggest the following code may be more along the lines of what you are trying to accomplish:

public static void main (String[] args) throws java.lang.Exception {
        for (int i = 0; i < 10; i++) {  
            new Thread1().start();  
        }  
}

//no need for this to be an instance method, or internally synchronized
public static int getNum(int i) {  
       return i + 1;  
}

static class Thread1 extends Thread {  
    static Integer value = 0;  

    @Override  
    public void run() {  
        while (value < 100) {
            synchronized(Thread1.class) {  //this ensures that all the threads use the same lock
                value = getNum(value);  
                System.out.println("Thread-" + this.getId() + ":  " + value);  
            }

            //for the sake of illustration, we sleep to ensure some other thread goes next
            try {Thread.sleep(100);} catch (Exception ignored) {} 
        }
    }  
}

Live example here: http://ideone.com/BGUYY

Note that getNum() is essentially superfluous. The example above would work the same if you replaced value = getNum(value); with a simple value++;.

Sign up to request clarification or add additional context in comments.

1 Comment

The example Sequential Id generator my Architect gave me also used a synchronized code block. I re-wrote it with an AtomicLong (AtomicInteger in your case) and we got a 40% performance boost. Umm.. oh. Crud this is THREAD sequential? That probably adds a wrinkle or two.
2

Though one wonders why this is necessary, here is one way to do it. It is not elegant but represents a minimal change to the original program:

import java.util.concurrent.*;

public class TestSync {

    public static void main(String[] args) {

    ExecutorService service = Executors.newSingleThreadExecutor();
    for (int i = 0; i < 10; i++) {
        service.submit(new Thread1());
    }

}

public int getNum(int i) {
    synchronized (this) {
        i++;
    }
    return i;
}

static class Thread1 implements Runnable {
    static Integer value = 0;
    @Override
    public void run() {
        TestSync ts = new TestSync();
        value = ts.getNum(value);
        System.out.println("thread1:" + value);
    }
}

}

Here is a version that is better. It uses an AtomicInteger for the counter (which is probably overkill in this case) to remove the unpleasant getNum() method:

import java.util.concurrent.*;
import java.util.concurrent.atomic.*;

public class TestSync {  
    static private AtomicInteger i = new AtomicInteger(0);

    public static void main(String[] args) {  
        ExecutorService service = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 10; i++) {  
            service.submit(new MyThread(i));  
        }  
        try { Thread.sleep(2*1000); } catch(Exception ex) {}
        service.shutdown();
    }  

    static class MyThread implements Runnable {  
        private int num = 0;
        public MyThread(int num) {
            this.num = num;
        }
        @Override  
        public void run() {  
            int value = i.incrementAndGet();
            System.out.println("thread # " + num + " value = " + value);  
        }  
    }  
}  

Comments

1

Not to mention, there is no guarantee of what order codes gets executed when running in threads. This is caused by what is called timeslicing. The CPU will allocate "slices" of time to a particular thread. When the slice is up, it effectively pauses the thread, and allows other threads to get a slice. Eventually, it will get back to paused threads and give them additional timeslices, but that's really up to the CPU.

Having multiple cores and/or hyperthreading allows the CPU(s) to have more threads be given a timeslice concurrently.

However, as i've said, there's no guarantee in which order threads are timesliced and where and when each individual thread will pause and resume.

What this means is that the order in which the "i++" operation (along with the associated print) is done is not necessarily the order in which you start your threads. In addition, any shared variable between threads should really be declared with the "volatile" modifier to prevent thread level caching of the value.

If you want to force sequential ordering, you should call into question why you are using threads in the first place instead of sequential loop.

Comments

0

I'm not a Java programmer, but a synchronization lock does not prevent getNum() from being invoked out of order. And because Thread1 is run on separate threads, the scheduler is free to run the 10 threads in any order.

What the synchronization does guarantee is that only one thread can be executing the code inside the synchronization section at a time.

If you want sequential execution, call all the getNums() in one thread. Or use a thread queue like ExecutorService.

Comments

0

There are 2 problems actually.

1). The Synchronization block is specific to a Thread1 instance

You should use either

 synchronized(TestSync.class) {  
                //  
                //
            }

or

synchronized(Thread1.class) {  
                //  
                //
            }

2). The core problem is that. Setting the static variable and your System.out.println() should also be synchronized so that generation and printing the values will be in sequence.

Comments

0

rewrite your main() method like:

public static void main(String[] args)
{
    for (int i = 0; i < 10; i++)
    {
        Thread th = new Thread(new Thread1());
        th.start();
        try
        {
            th.join();
        }
        catch (InterruptedException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.