繁体   English   中英

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

[英]Implementing a "fence" object in Java without using threads

我的大学教授给我分配了一个练习,内容如下:

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

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

因此,只有当调用相同数量的 notify() 和队列中的对象(也就是 add(Object) 的数量)时,await() 才会终止,并且队列中的 object 最终会添加到集合中。 <- 这是我在编写代码后弄错并意识到的

我做了如下实现:

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();

        
        
    }   
}

提交给我的教授后,我被告知两件事:

  1. 同步不正确:等待在第一次通知后“解锁”,这不应该发生,因为它不等待队列中的其他(如果有)对象得到通知。
    ^让我说我知道如何轻松解决这个问题,但是
  2. 尽管这是一个小错误,但方法 await、add 和 notification 不应该使用异步专用线程来完成。

我的问题终于来了。 如果我不使用专用线程,我应该如何在锁 object 上使用 wait() 然后 notify() ? 我尝试删除线程,但显然只要我调用 mutex.wait() 程序就会锁定,并且调用通知方法之后的代码不会到达。

为什么我的教授告诉我使用线程是错误的? 如何在没有程序锁定的情况下使用 wait() 然后在两个单独的方法中调用 notify()?

这是我的意思的一个例子:

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(); 
        
    }

在不使用线程的情况下,当我调用 startWait() 时,主线程会进入等待状态,但是无法调用 sendNotify() 并且程序会冻结。 有没有办法在不使用线程的情况下做到这一点,或者我错过了什么?

非常感谢。

有人告诉我...虽然这是一个小错误,但方法 await、add 和 notification 不应该使用异步专用线程来完成。

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

您的await()方法不会等待。 它创建一个新线程,然后立即返回。 新线程等待某些东西,但之后它就死了,没有做任何有用的事情。 新线程可能根本不存在。

您的add(o)方法也没有多大意义。 我什至不确定你想用它做什么,但我认为你需要退后一步,试着向鸭子解释为什么你认为这两种方法中的任何一种都应该创建一个新线程。


如果我不使用专用线程,我应该如何在锁 object 上使用 wait() 然后 notify() ?

Oracle“受保护的块”教程是老歌,但很好。 如果你一直工作到最后,它应该让你非常清楚地知道如何以及为什么以及何时使用wait()notify()

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

暂无
暂无

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

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