简体   繁体   English

在不使用线程的情况下在 Java 中实现“栅栏”object

[英]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: ". “栅栏 object 是一个 object,它有一个对象集合,并且可以等待任何这些对象发出信号。有一个 add(Object) 方法,它添加了一个 object 方法到集合中。还有一个 await) 方法。 :这允许等待要发出信号的集合的任何 object。每当在 await() 方法处于活动状态时调用 add(Object) 方法时,add 的参数都会放入队列中。使用以下代码编写源代码界面: ”。

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.因此,只有当调用相同数量的 notify() 和队列中的对象(也就是 add(Object) 的数量)时,await() 才会终止,并且队列中的 object 最终会添加到集合中。 <- 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.尽管这是一个小错误,但方法 await、add 和 notification 不应该使用异步专用线程来完成。

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?如果我不使用专用线程,我应该如何在锁 object 上使用 wait() 然后 notify() ? 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.我尝试删除线程,但显然只要我调用 mutex.wait() 程序就会锁定,并且调用通知方法之后的代码不会到达。

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?如何在没有程序锁定的情况下使用 wait() 然后在两个单独的方法中调用 notify()?

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.在不使用线程的情况下,当我调用 startWait() 时,主线程会进入等待状态,但是无法调用 sendNotify() 并且程序会冻结。 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.有人告诉我...虽然这是一个小错误,但方法 await、add 和 notification 不应该使用异步专用线程来完成。

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.一个名为await()的方法的全部意义在于,它不应该在调用者想要等待的事件发生之前返回

Your await() method doesn't wait.您的await()方法不会等待。 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.您的add(o)方法也没有多大意义。 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?如果我不使用专用线程,我应该如何在锁 object 上使用 wait() 然后 notify() ?

The Oracle "Guarded Blocks" tutorial is an oldie but a goodie. Oracle“受保护的块”教程是老歌,但很好。 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() .如果你一直工作到最后,它应该让你非常清楚地知道如何以及为什么以及何时使用wait()notify()

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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