Notification and waiting script

public class NotifyAndWaitExample2 {
    static int i = 0;

    public static void main(String[] args) {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (this) {
                    if (i <= 0) {
                        System.out.println("i=" + i + "in t1");
                        System.out.println(Thread.currentThread().getName() + "is running");
                        try {
                            wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println(Thread.currentThread().getName() + "is waken up");
                }
            }
        });
        Thread t4 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (this) {
                    i++;
                    System.out.println("i=" + i + "in t4");
                    System.out.println(Thread.currentThread().getName() + "is notifying");
                    try {
                        Thread.sleep(1000);
                        notify();
                        System.out.println("notified");
                    } catch (InterruptedException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
                }
            }
        });
        t1.start();
        t4.start();
    }
}

      

The icon is displayed here: -

i=0in t1 
i=1in t4 
Thread-0is running 
Thread-1is notifying 
notified 

      

The one last line should also be printed on the ie output; " Thread-0 is waken up

". Why after printing the "notification" it will not lose the lock for the thread "t1 run () method" and continue the code after waiting () in t1. those. it should print "Thread-0 waken up" after printing "notice".

+3


source to share


4 answers


Your blocks synchronized

have a no effect.

Yours synchronized(this)

just acquires the lock on the instance Runnable

where you also implement the method run

.

Your theme t1

will never be notified, it is waiting Runnable

where you use the method wait()

to receive the notification. The only object that contains a reference to this Runnable is Thread

Object t1

and which (usually) won't call notify()

or notifyAll()

in this Runnable.

I am using int[]

to store int value as well as hold lock / monitor. The decision is only to show you how you could have done it, it does not mean that it is good practice to do it this way.



I would recommend reading a good tutorial on how synchronization works in Java.

I modified your example to work as you expect.

public class NotifyAndWaitExample2 {
    private static int[] i = {0};

    public static void main(String[] args) {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (i) {
                    if (i[0] <= 0) {
                        System.out.println("i=" + i[0] + " in t1");
                        System.out.println(Thread.currentThread().getName() + " is running");
                        try {
                            i.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println(Thread.currentThread().getName() + " is waken up");
                }
            }
        });
        Thread t4 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (i) {
                    i[0]++;
                    System.out.println("i=" + i[0] + "in t4");
                    System.out.println(Thread.currentThread().getName() + " is notifying");
                    try {
                        Thread.sleep(1000);
                        i.notifyAll();
                        System.out.println("notifying");
                    } catch (InterruptedException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
                }
            }
        });
        t1.start();
        t4.start();
    }
}

      

+2


source


you are blocking two different objects. in your example, "this" refers to each of the executable instances. Also, the variable "i" must be volatile (otherwise different threads won't see the latest changes)

see below:



public class NotifyAndWaitExample {

    private volatile int i = 0;
    private Object lock1 = new Object();

    public static void main(String[] args) {
        NotifyAndWaitExample notifyAndWaitExample = new NotifyAndWaitExample();
        notifyAndWaitExample.execute();
    }

    private void execute() {


        Thread t1 = new Thread(new Runnable() {

            @Override
            public void run() {
                synchronized (lock1) {
                    if (i <= 0) {
                        System.out.println("i= " + i + " in t1");
                        System.out.println(Thread.currentThread().getName() + " is running");

                        try {
                            lock1.wait();

                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println(Thread.currentThread().getName() + " is waken up");
                }
            }
        });

        Thread t4 = new Thread(new Runnable() {

            @Override
            public void run() {
                synchronized (lock1) {
                    i++;
                    System.out.println("i= " + i + " in t4");
                    System.out.println(Thread.currentThread().getName() + " is notifying");
                    try {
                        Thread.sleep(1000);
                        lock1.notify();
                        System.out.println("notified");
                    } catch (InterruptedException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
                }
            }
        });


        t1.start();
        t4.start();
    }

}

      

+1


source


public class NotifyAndWaitExample2 {
    static int i = 0;

    public static void main(String[] args) {
        Object lock = new Object();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock) {
                    if (i <= 0) {
                        System.out.println("i=" + i + "in t1");
                        System.out.println(Thread.currentThread().getName() + "is running");
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println(Thread.currentThread().getName() + "is waken up");
                }
            }
        });
        Thread t4 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock) {
                    i++;
                    System.out.println("i=" + i + "in t4");
                    System.out.println(Thread.currentThread().getName() + "is notifying");
                    try {
                        Thread.sleep(1000);
                        lock.notify();
                        System.out.println("notified");
                    } catch (InterruptedException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
                }
            }
        });
        t1.start();
        t4.start();
    }
}

      

+1


source


Your current problem is that you are syncing the wrong (different) object (s). As you say, "synchronized (this)" in your code, "this" is the current instance of the thread. Since you have two of them, the sync will fail.

I really suggest thinking in monitors. The monitor is a ressource wrapper that restricts concurrency to maintain internal consistency of state. I've refactored your code to use a monitor.

public class NotifyAndWaitExample2 {

    private static class Monitor {

        // Resource
        private int i;


        public synchronized void operation1() {

            if (i <= 0) {
                System.out.println("i=" + i + "in t1");
                System.out.println(Thread.currentThread().getName() + "is running");
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName() + "is waken up");

        }


        public synchronized void operation2() {

            i++;
            System.out.println("i=" + i + "in t4");
            System.out.println(Thread.currentThread().getName() + "is notifying");
            try {
                Thread.sleep(1000);
                notify();
                System.out.println("notified");
            } catch (InterruptedException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }

        }

    }

    public static void main(String[] args) {

        Monitor monitor = new Monitor();

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                monitor.operation1();
            }
        });

        Thread t4 = new Thread(new Runnable() {
            @Override
            public void run() {
                monitor.operation2();
            }
        });

        t1.start();
        t4.start();

    }
}

      

"wait ()" and "notify ()" are now executed on the SAME object, so the running threads will be synchronized.

+1


source







All Articles