简体   繁体   中英

Implementing a "fence" object in Java without using threads

I have been assigned an exercise from my uni professor that goes as follow:

"A fence object is an object that has a collection of objects, and can wait on any of those objects is signaled. There is an add(Object) method, which adds an object to the collection. There is also an await() method: this allows to wait on any object of the collection to be signaled. Whenever the add(Object) method is called while the await() method is active, the argument of the add is put in queue. Write the source code using the following interface: ".

public interface Fence {
    public void await() throws InterruptedException; 
    public void add(Object o); 
}

So, only when the same number of notify() and objects in queue (aka the number of add(Object) ) are called, the await() terminates and the object in the queue are finally added to the collection. <- this is something I got wrong and realized after writing my code

I did make the implementation as follow:

import java.util.LinkedList;

public class FenceImpl2 implements Fence{
    
    private LinkedList<Object> collection; 
    private Object mutex; ; 
    static boolean iswaiting = false; 
    
    public FenceImpl2() {
        this.collection = new LinkedList<Object>(); 
        this.mutex = new Object(); 
    }

    @Override
    public void await() throws InterruptedException {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    synchronized(mutex) {   
                    mutex.wait();
                    iswaiting = true; 
                        }
                    } catch (InterruptedException e) {
                            e.printStackTrace();
                        }}}); 
            t1.start(); 
        }

    @Override
    public void add(Object o) {
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized(mutex){
                    if(iswaiting == true) {
                        try {
                            mutex.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        } 
                    }
                    else {
                        collection.add(o);
                    }
                }}}); 
        t2.start(); 
    }
    
    public Object getList() throws InterruptedException {
        synchronized(mutex){
            System.out.println("Collection list:  \n"); 
        for(Object o : collection) {
            System.out.println(o); 
            Thread.sleep(1000);
        
        } 
        System.out.println("------- \n"); 
        return collection;
        }
    }
    
    public void notification() {
            Thread thread = new Thread(()->{
                synchronized(mutex){
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    mutex.notify();
                    }
                });
            
                thread.start();
    }
    
    
    public static void main(String[] args) throws InterruptedException {
        
        FenceImpl2 f = new FenceImpl2(); 
        Object o1 = 1; 
        Object o2 = 2; 
        Object o3 = 3; 
        Object o4 = 70; 

        f.add(o1);
        System.out.println("Add 1");
        f.add(o2); 
        System.out.println("Add 2");
        f.add(o3);
        System.out.println("Add 3");
        f.await();
        System.out.println("Await active ");
        f.add(o4);
        System.out.println("Aggiungo 70 - Shouldn't appear. Forced in queue");
        f.getList();
        f.notification();
        System.out.println("Notify() sent - 70 should now appear in the collection");
        f.getList();

        
        
    }   
}

After submitting it to my professor I have been told two things:

  1. The synchronization is not correct: the await "unlocks" after the first notify and that shouldn't happen because it doesn't wait for the other (if any) objects that are in queue to be notified.
    ^Let me say I know how to fix that easily but
  2. Although it's a minor mistake, the methods await, add and notification SHOULD NOT be done using asynchronous dedicated threads.

Here it finally comes my problem. How am I supposed to use wait() on a lock object and then notify() if I am not using dedicated threads? I tried removing the threads but obviously as soon as I'm calling mutex.wait() the program locks and the code right after that calls the notification method is not reached.

Why did my professor tell me using threads is wrong? How can I use a wait() and then call a notify() in two separate methods without having the program lock?

Here's an example of what I mean:

public class testw {
    
    private Object mutex; 
    boolean condition = false; 
    
    
    public testw() {
        this.mutex = new Object();
    }
    
    public void startWait() {
        synchronized(mutex) {
            try {
                Thread.sleep(1000);
                condition = true; 
                while(condition == true) {
                    System.out.println("Waiting!");
                    mutex.wait();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }           
        }
    }
    
    public void sendNotify() {
        synchronized(mutex) {
            try {
                Thread.sleep(3000);
                System.out.println("Notify!, not waiting anymore");
                condition = false; 
                mutex.notify();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } 
        }
    }
    
    public static void main(String[] args) {
        
        testw t = new testw(); 
        
        t.startWait();
        t.sendNotify(); 
        
    }

Without using threads, when I startWait() is called the main thread goes in wait, but there's no way that sendNotify() to be called and the programs freezes. Is there a way to do this without using threads or am I missing something?

Thank you very much.

I have been told...Although it's a minor mistake, the methods await, add and notification SHOULD NOT be done using asynchronous dedicated threads.

The whole point of a method named await() is that it should not return until the event that the caller wants to wait for has happened.

Your await() method doesn't wait. It creates a new thread and then it immediately returns. The new thread waits for something, but after that it just dies without doing anything useful. The new thread might as well not exist at all.

Your add(o) method doesn't make a whole lot of sense either. I'm not even sure what you were trying to do with it, but I think you need to take a step back, and try to explain to the duck why you thought that either of those two methods should create a new thread.


How am I supposed to use wait() on a lock object and then notify() if I am not using dedicated threads?

The Oracle "Guarded Blocks" tutorial is an oldie but a goodie. If you work through it to the end, it should give you a pretty clear idea of how and why and when to use wait() and notify() .

https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM