Mouhammad Mouhammad - 4 months ago 6
Java Question

How does a synchronized method work in Java?

I need a method that will run only once from the background no matter how many threads call it.
I found a partial solution using this code
my code:

public static void async(final int a){
Thread th = new Thread(new Runnable() {
@Override
public void run() {
meth(a);
}
});
th.start();
}
public static synchronized void meth(final int a){
try {
Thread.sleep(1000);
System.out.println(a);
} catch (InterruptedException ex) {
Logger.getLogger(Simple.class.getName()).log(Level.SEVERE, null, ex);
}
}


But when I test it like that:

System.out.println("start");
async(11);
async(12);
async(13);
async(14);
async(15);
async(16);
async(17);
async(18);
async(19);
System.out.println("end");


I got those results:

start
end
11
19
18
17
15
16
14
13
12

Is there anything wrong with my code?
Why the results are not in the same order as the call?

edited
after using Thread.join

public static Object obg = new Object();

public static void async(final int a){
Thread th = new Thread(new Runnable() {
@Override
public void run() {
meth(a);
}
});
th.start();
try {
th.join();
} catch (InterruptedException ex) {
Logger.getLogger(Simple.class.getName()).log(Level.SEVERE, null, ex);
}
}

public static synchronized void meth(final int a){
try {
Thread.sleep(1000);
System.out.println(a);
} catch (InterruptedException ex) {
Logger.getLogger(Simple.class.getName()).log(Level.SEVERE, null, ex);
}
}


i got this result which cancled the background work :

start
11
12
13
14
15
16
17
18
19
end

Thread.join didn't gave me the results I wish

edit for the third time to give example from other languages.

I tried the same code in c#

static void Main(string[] args)
{
Console.WriteLine("start");
async(11);
async(12);
async(13);
async(14);
async(15);
async(16);
async(17);
async(18);
Console.WriteLine("end");
}

static Object o = new Object();
public static void async(int a){
new Thread(() =>
{
lock (o)
{
Thread.Sleep(1000);
Console.WriteLine(a);
}
}).Start();
}


the results was in the same order

test results from swift language are the same as c#

so my question is : how to achieve those results in java

edit :
results of using the newly created thread in the join

code :

public static void main(String[] args) throws Exception {
System.out.println("start");
async(19,async(18,async(17,async(16,async(15,async(14,async(13,async(12,async(11,null)))))))));
System.out.println("end");
}

public static Object obg = new Object();

public static Thread async(final int a,final Thread other){
Thread th = new Thread(new Runnable() {
@Override
public void run() {
meth(a);
}
});
th.start();
try {
if(other!=null){
other.join();
}
} catch (InterruptedException ex) {
Logger.getLogger(Simple.class.getName()).log(Level.SEVERE, null, ex);
}
return th;
}

public static synchronized void meth(final int a){
try {
Thread.sleep(1000);
System.out.println(a);
} catch (InterruptedException ex) {
Logger.getLogger(Simple.class.getName()).log(Level.SEVERE, null, ex);
}
}


results :

start
11
12
13
14
15
16
17
18
end
19

background work was also canceled.

Answer

Your main thread starts nine others, giving each child thread a different a, and the first thing that all nine of those child threads do is sleep for one second.

The timing resolution in the Thread.sleep() call is undefined---It depends on the underlying operating system---and it's quite possible that all of the threads were elgible to wake up on the same tick of the system clock.

Java makes no guarantee that the threads will start running in the order that their Thread objects were start()ed, and it makes no guarantee that they will wake up in the order in which they went to sleep.

Any time you want things to happen in a certain order, the best way to make that happen is to do all of the things in a single thread.


I need this section to run sequentially...I don't want it to run twice or more at the same time...I still want it to run in the background.

OK., I get it now.

You probably want to use java.util.concurrent.Executors.newSingleThreadExecutor(). That function will return a thread pool with a single worker thread.

The worker thread will run tasks that you submit to the pool "in the background", and it will run them, one at a time, in the order that they were submitted.

static final ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();

public static void async(final int a) {
    singleThreadExecutor.submit(new Runnable() {
        @Override
        public void run() {
            meth(a);
        }
    });
}