4

I have two threads in my java programme, one is main thread and other thread is thread A which is spawned in main thread. now i want main thread to start thread A and wait till thread A has executed some part of its code in run method and thread A should suspend itself. main thread should then start running, run few lines of code and then again thread A should start from where it has stopped and vice versa. this should happen for n number of times. I am trying as belows:

Thread A class:

public class ThreadA implements Runnable {
    boolean suspended = false;
    boolean stopped = false;
    synchronized void stop() {
        stopped = true;
        suspended = false;
        notify();
    }
    synchronized void suspend() {
        suspended = true;
    }
    synchronized void resume() {
        suspended = false;
        notify();
    }
    void job() throws InterruptedException {
        for (int i = 0; i < 5; i++)
            synchronized (this) {
                System.out.println("performing job.");
                suspend();
                while (suspended) {
                    notify();
                    suspended = false;
                }
            }
    }
    @Override
    public void run() {
        try {
            job();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

MainThread:

public class MainThread {
    public static void main(String[] args) throws InterruptedException {
        ThreadA a1=new ThreadA();
        Thread t1=new Thread(a1);
        synchronized (t1) {
            t1.start();
            for (int i = 0; i < 5; i++) {
                t1.wait();
                System.out.println("perform some action");
                a1.resume();
            }

        }
    }
}

Expected output:

performing job.
perform some action
performing job.
perform some action
performing job.
perform some action
performing job.
perform some action
performing job.
perform some action

Actual output:

performing job.
performing job.
performing job.
performing job.
performing job.
perform some action

I don't know why the whole for loop is getting executed in Thread A even when i've issued a notify() signal in job method.

Keppil
  • 45,603
  • 8
  • 97
  • 119
Mrunal Gosar
  • 4,595
  • 13
  • 48
  • 71
  • 3
    if it's not for education, why would you run 2 Threads, that execute one after another? you can do exactly the same with only 1 thread – JohnnyAW Jul 11 '14 at 11:12
  • 3
    Sidenote: you synchronize the two threads on different objects, thus the `synchronized` statements are pretty useless. – Thomas Jul 11 '14 at 11:12
  • are you expecting completely random? or action-job-action-job in step? – Oliver Watkins Jul 11 '14 at 11:13
  • @coreJavare `suspend()` is a custom method here. – Thomas Jul 11 '14 at 11:14
  • Why do you call your Runnable implementation `Thread`? It is not a thread. – isnot2bad Jul 11 '14 at 11:19
  • 1
    What is the point of having two threads if one is just going to wait for the other? – Christoffer Hammarström Jul 11 '14 at 11:24
  • In my point of view this implementation isn't based on a correct knowledge of concurreny mechanisms in Java. For a correct response it's necessary construct a different example, you can start from different threads in stackoverflow like this: http://stackoverflow.com/questions/8982523/java-access-an-object-in-different-threads – m.genova Jul 11 '14 at 11:33
  • @m.genova, this type of ['ping pong'](http://mechanical-sympathy.blogspot.co.uk/2011/08/inter-thread-latency.html) code snippet can be used to measure latency. – Chris K Jul 11 '14 at 11:37
  • Hi all my requirement is, MainThread is running some job, it will dump some actions in serialized object. which then Thread A will read perform that action and dump the result in a serialized result object. After then the MainThread will read the result object and keep another job in serialized object for Thread A. – Mrunal Gosar Jul 11 '14 at 13:49
  • The problem is i have two applications and both cannot interact with each other directly. so i am starting both of them in threads and trying to establish handshaking between them. – Mrunal Gosar Jul 11 '14 at 13:50

4 Answers4

2

You have two bugs here.

The first is that you are synchronizing and notifying different objects. Try this modified main, I changed synchronized (t1) to synchronized (a1) and t1.wait() to a1.wait().

public static void main(String[] args) throws InterruptedException {
    ThreadA a1=new ThreadA();
    Thread t1=new Thread(a1);

    synchronized (a1) {    // CHANGED FROM t1 to a1
        t1.start();
        for (int i = 0; i < 5; i++) {
            a1.wait();    // CHANGED FROM t1 to a1
            System.out.println("perform some action");
            a1.resume();
        }

    }
}

The second bug is in the job() method, it calls notify() but not wait(). Here is a fixed version:

void job() throws InterruptedException {
    for (int i = 0; i < 5; i++)
        synchronized (this) {
            System.out.println("performing job.");
            suspend();
            while (suspended) {
                notify();
                suspended = false;
                wait();    // ADDED
            }
        }
}

The output from my test run is

performing job.
perform some action
performing job.
perform some action
performing job.
perform some action
performing job.
perform some action
performing job.
perform some action
Chris K
  • 11,622
  • 1
  • 36
  • 49
  • @mmc18, yes I had but you have made me realise that I have made an omission. I had fixed another bug that I had mentioned in the comments up the top but had not put into this answer. Thank you for pointing this out, I have fixed the answer. – Chris K Jul 11 '14 at 11:40
  • @ChrisK tried your answer and it is working. silly mistake was holding on to thread object. dumb me. – Mrunal Gosar Jul 11 '14 at 14:07
1

Here is more simplified way

public class TwoThread {

    public static void main(String[] args) throws InterruptedException {
        ThreadA a1 = new ThreadA();
        Thread t1 = new Thread(a1);

        synchronized (a1) {
            t1.start();
            for (int i = 0; i < 5; i++) {
                a1.wait();
                System.out.println("perform some action " + i);
                a1.notify();
            }

        }
    }
}

public class ThreadA implements Runnable {
    boolean suspended = false;
    boolean stopped = false;

    void job() throws InterruptedException {
        for (int i = 0; i < 5; i++)
            synchronized (this) {
                System.out.println("performing job. " + i);
                notify();
                wait();
            }
    }

    public void run() {
        try {
            job();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

}
Ahmet Karakaya
  • 9,899
  • 23
  • 86
  • 141
  • thanks @mmc18 i had tried above earlier, but because of silly mistake of holding thread lock i was not able to figure out why notify and wait where not working. After trying the corrections now i don't need custom suspend and stop methods. Thanks. Accepting your answer. – Mrunal Gosar Jul 11 '14 at 14:09
  • I've again run into some issue, please help me out. The job that i am running in opens up in daemon thread, so whenever i start thread t1 and loose objects lock, the lock is then acquired by daemon thread, which processes some lines and from there onwards both my threads into loose lock and are waiting indefinitely. what can be the possible solution for this? – Mrunal Gosar Jul 14 '14 at 15:48
1

To communicate between two threads only:

  1. You do not need synchronized
  2. You do not need locks
  3. You do not need CAS (Compare And Swap). (Neither weak or strong)
  4. You do not need setOpaque, setVolative nor setRelease

You just need VarHandle barrier (in Java). Java VarHandle The only requirement is ordered memory access

Here is a reasonably good article. Synchronizing without Locks and Concurrent Data Structures

In my daily work, I use variants of Dekker's and Peterson's algorithm for asynchronous multi-threaded processing of web requests, sharing connection pools and collecting logs from cloud application with minor impact on performance compared to the single thread un-contended performance.

Occasionally, I have to use setOpaque and getOpaque, with VarHandle.loadLoadFence() and VarHandle.storeStoreFence() to ensure ordered memory access and that is all you would need. In my view the weak CAS is the furthers I would go, as anything else I see as a violation of the multi-core CPU architecture.

However, unless you have an in-depth understanding of the actual hardware that you are using and memory ordering constructs used at the micro-instruction level, I suggest you use standard Java concurrent locks, as they are the best and optimal for general-purpose solutions.

To achieve, 10 x performance boost over the conventional CAS algorithms, you need to make very stable layout of all shared objects in memory and to strictly define which threads can read and which can write to each variable and in which order. You will need to consider the side effect on the CPU cache of all memory loads and stores, and then to get these to work in your advantage on the specific platform that you are targeting. You will end up with quite complex algorithms, but unbeatable performance.

You should explore the LMAX Disruptor library as it has the open source library that implements many of these concepts like ring-buffers and single thread can write to each variable. LMAX Disruptor User Guide Yet, I still see this as the the conservative approach to concurrency. My current standard is to have algorithm that tolerate racing and discard data and repeat processing if they detect racing condition. I use the state embeded counters, indexes, flags and hashes, to detect thread collision and chose thread that will give up and use another memory structure for its operation. However, due to thread focused memory structures and optimized reference sharing these occur rarely (like one in 1 million)

Yet, if you have good understanding of CPU cache operations and any specialized platform instruction you can get CPU cache to work in your advantage and execute reads and writes, and sharing of cache lines between cores, as a side effect of your instructions without you having to explicitly issue commands to do this.

BTW, the NodeJS (V8) engine was an attempt to minimize contention and locking by having a single thread event loop to distribute events to all other I/O and utility library threads, so they do not have to compete between themselves for access to events and shared memory. As you can see, NodeJS had great success, and if we are talking about the special purpose algorithms you can take it even further. NodeJS architecture

Happy reading.

mindiga
  • 509
  • 3
  • 18
  • I really like your answer. It appears you have a lot of knowledge on the subject. I'll add a longer response shortly. – pveentjer Jul 08 '21 at 03:33
  • AFAIK if you use plain loads/store in combination with e.g. a loadload/storestore-fence, there is one potential problem: atomicity. So if you would be using a long/double field and run on a 32 bits platform (very unlikely) then you could run into problems like a torn read or write. – pveentjer Jul 08 '21 at 03:51
  • If only 2 threads. For more than 2 threads you need CAS. However, you can use the single governing thread to exchange payload references between multiple threads, in which case you get just two threads at any time. Regarding atomicity, you are right for 32 bit. But I deal with only 64 bit pointers. If your data is on a single cache line, then atomicity is implied anyway as soon as you do a write through store on that cache line. Takes time to master it. – mindiga Jul 10 '21 at 17:23
  • I'm not sure how the write through store fits in. Modern caches are write behind. Atomicity on the x86_64 for 64 bits fields is easy; the compiler just needs to naturally align it. And it indeed takes a lot of time to master. I'm still learning every day. – pveentjer Jul 10 '21 at 18:12
0

There is little reason to synchronize multiple threads if one threads waits while another does its thing. One could use Executors to get the same result with less work and still got the feeling that one is playing with the threads.

public class Main {

    public static void main(String[] args) {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        for(int i = 0; i<5;i++) {
            executor.submit(new PrintTask("performing job."));
            executor.submit(new PrintTask("perform some action"));
        }
        executor.shutdown();
    }

    private static class PrintTask implements Runnable {
        private String string;

        public PrintTask(String string) {
            this.string = string;
        }

        @Override
        public void run() {
            System.out.println(string);
        }
    }

}
Panu
  • 362
  • 3
  • 13
  • You do not want to many threads blocked waiting on I/O as it involves costly switching of the thread context to park and unpark the thread. You want a fewer threads that are running for longer with minimal synchronization between them – mindiga Jun 25 '21 at 08:32