簡體   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