簡體   English   中英

是否可以等待非Threads中的方法在Java中完成?

[英]Is it possible to wait for methods that aren't in Threads to finish in Java?

我有一個進行一些計算的對象,然后對於每個迭代,我想畫出發生的情況。 在繪制過程中,我希望它等待。

這是我所做的,基本上是:

synchronized public void compute()
{
    other.mark(variable);
    try
    {
        wait();
    }
    catch(InterruptedException e)
    {
    }
}

在OtherClass中,我有

synchronized public void mark(int var)
{
    //change some stuff
    repaint();
    notify();
}

發生的事情是compute()永遠等待。 我認為這將行得通,因為編譯器未給出任何錯誤。 這兩個類都沒有實現Runnable或擴展Thread,所以也許是問題所在嗎? 我不確定,因為我認為如果這些對象不能使用此類方法,我會被警告。

我想這可能是關於程序本身的邏輯的錯誤,但總的來說,這就是我所擁有的。

您的問題建議您要執行一些操作,以在完成時更新GUI狀態或將其進度通知給GUI。 這就是SwingWorker的目的。 對於這兩種情況,鏈接的javadoc上都有一些示例。

這根本無法像您想象的那樣起作用。 從Javadoc的wait()方法開始(重點是我):

使當前線程等待,直到另一個線程為此對象調用notify()方法或notifyAll()方法。

程序中顯然沒有其他線程可以喚醒休眠的compute()方法。

為了解決您的特定問題,您要么必須有兩個線程,要么要以可恢復的方式實現compute()方法,這在偽Java中是這樣的:

ComputeStatus status = new ComputeStatus();
do {
    compute(status);  // compute iteration
    mark(status);     // draw iteration
    status.next();    // next iteration
} while (!status.isFinished());

在這里, ComputeStatus保持計算的當前狀態,而comupte()知道如何從該狀態繼續計算。 無論是在compute()還是在主循環中更改狀態,都取決於您和您要解決的問題。

Object.wait()和Object.notify()僅供線程使用。 在顯示的代碼中,mark(int var)方法直到完成才返回,無需等待。 此外,僅在多線程程序中才需要同步方法。

您的代碼應為:

public void compute()
{
    other.mark(variable);
}

public void mark(int var)
{
    //change some stuff
    repaint();
}

由於您的程序是一個GUI程序(我通過repaint()調用收集),因此它固有地是多線程的,即使您不知道它也是。 (如果沒有,它將表現得很差。)

如果您不使用線程,則不能使用等待/通知或任何其他類型的同步,因為沒有兩個線程可以同步。 但是,不必一定要在GUI程序中顯式地使用線程來最終使用線程。

請注意,如果您使用依賴線程的方法,但實際上不以任何方式使用線程,則Java編譯器不會警告您。

您遇到以下問題之一:

1)您正在使用線程而不知道它,並且您正在使用兩個不同的監視對象。 因此,當您調用notify() ,它會通知該對象的監視器,而不是您正在調用wait()的第一個對象的監視器。 有許多可能的解決方案。 最簡單的方法之一是使用JDK 5並發實用程序執行此操作,該實用程序比內置的基本監視器等待/通知方法要好得多。 要么,

2)您正在單個線程中運行,並且等待/通知不好。 在單線程程序中等待另一個線程通知只是沒有意義-沒有其他線程可以這樣做。

假設您實際上使用了多個線程,使用Java 5和更高版本解決此問題的一個好方法是使用信號燈 ,也許通過在包含mark()的類中進行簡化:

private final Semaphore sem = new Semaphore(1);

public void mark(int var) {
  sem.acquire();
  //change some stuff
  repaint();
  sem.release();
}

waitForSemaphore() {
  sem.acquire();
}

然后在compute ,當您想等待被mark()通知時,調用waitForSemaphore() mark() 因為mark()已經獲取了信號量,所以您必須等待mark()釋放信號量,然后計算才能通過調用waitForSemaphore()來獲取它。

repaint方法記錄了需要繪制組件的需要,但是實際上並沒有繪制組件,但是Java將在下次獲得對象時重新繪制對象。 如果您要制作動畫之類的東西,那么等待重繪就沒有目的了。 相反,我建議您使用計時器。 現在,您有2個計時器選項。 如果您要更新不需要精確計時的內容,那么通常需要使用javax.swing.Timer。 您可以這樣使用它:

//imports (before class definition)
import javax.swing.Timer;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

//put this code where you want to start doing calculations
int delay = 1000; //milliseconds
ActionListener taskPerformer = new ActionListener() {
    public void actionPerformed(ActionEvent evt) {
        //update your calculations
        model.calculate();
        //tell Java to call paint at the next chance it gets
        viewer.repaint();
    }
};
new Timer(delay, taskPerformer).start();

在上面的代碼中,模型是您要對其執行計算的對象,查看器是根據模型進行繪制的對象。

Swing計時器的計時不是很精確,這在很多情況下都很好,但是有時您需要更精確地計划代碼。 在這種情況下,您可能要使用java.util.Timer類。 您可以這樣使用它:

//imports (before class definition)
import java.util.Timer;
import java.util.TimerTask;

//inner class that does the calculations
public class CalculateTask extends TimerTask {
    public void run() {
        model.calculate();
        view.repaint();
    }
}

//put this code where you want to start doing calculations
int delay = 0;//time before running CalculateTask.run()
int repeat = 1000; //time between each subsequent rums of CalculateTask.run()
boolean isDaemon = true;//allow java to shutdown without stopping timer
Timer timer = new Timer(isDaemon);
timer.scheduleAtFixedRate(new CalculateTask(), delay, repeat); 

由於您沒有在同一個對象上進行同步,因此永遠不會釋放wait()。 您的計算方法位於另一個對象中,因此,通知調用與mark()方法共享的監視器不同。

等待/通知機制用於共享監視器,也就是說,它們必須共享相同的線程鎖定機制。

wait()將“喚醒”的唯一方法是,如果另一個線程從同一對象上的同步塊內調用notify()。

不幸的是,wait()永遠不會停止等待。 主要原因是,看您是否放置了notify()。 它是由同一線程調用的,無法將其自身喚醒。

這很簡單。 mark(int var)在您到達wait()命令時已經完成運行,因此mark(int var)中的notify()無法喚醒它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM