문제

스윙 애플리케이션에서 수행 할 두 가지 프로세스가 있습니다. 하나는 목록을 채우고, 하나는 목록의 각 요소에서 작업을 수행해야합니다. 작업이 수행되는 동안 GUI 잠금을 중지하기 위해 2 개의 프로세스를 SwingWorker 스레드로 옮겼습니다.이 작업 세트를 여러 목록으로 수행해야하므로 동시성은 첫 번째에서는 나쁜 생각이 아닙니다. 장소. 그러나 방금 달렸을 때

filllist.execute ();
dostufftolist.execute ();

Dostufftolist 스레드는 빈 목록에서 실행되었습니다 (Duh ...). 두 번째 프로세스에서 첫 번째 프로세스가 끝날 때까지 기다리라고 어떻게 말합니까? 나는 첫 번째 프로세스의 끝에서 두 번째 과정을 중첩 할 수 있다고 생각하지만, 노르 노, 그것은 나쁜 연습처럼 보인다.

도움이 되었습니까?

해결책

이런 일이 그렇게 할 것 같아요?

boolean listIsFull=false;
class FillListWorker extends SwingWorker<Foo,Bar>
{
    ...
    protected void done()
    {
        synchronized (listYouveBeenFilling)
        {
            listIsFull=true;
            listYouveBeenFilling.notifyAll();
        }
    }
    ...
}

class DoStuffToListListWorker extends SwingWorker<Foo,Bar>
{
    ...
    protected Foo doInBackground()
    {
        synchronized (listYouveBeenFilling)
        {
            while (!listIsFull)
            {
                try
                {
                    listYouveBeenFilling.wait();
                }
                catch (InterruptedException ie)
                {
                    // Don't worry, we'll just wait again
                }
            }
        }
    }
    ...
}

다른 팁

두 번째 프로세스에서 첫 번째 프로세스가 끝날 때까지 기다리라고 어떻게 말합니까? 나는 첫 번째 프로세스의 끝에서 두 번째 과정을 중첩 할 수 있다고 생각하지만, 노르 노, 그것은 나쁜 연습처럼 보인다.

대신 Callables & Futures를 사용해 보셨습니까? 그들은 이런 종류의 일과 잘 어울립니다 (DostuffTolist가 실제 목록 대신 미래에 대한 DostuffTolist가 작동하게하므로 전체 Swingworker 비즈니스와는 별도로 ... 이것을 대답보다는 제안으로 생각하십시오)

우리는 다음과 같은 것이 있습니다.

private SwingWorkerExecutor swingWorkerExecutor;

//...

protected void runChain(List<SwingWorker<Void>> chainWorkers,
                        final SwingWorkerExecutor.RunAfter<Void> runAfter,
                        final SwingWorkerExecutor.RunOnError runOnError)
{
    final List<SwingWorker<Void>> remainingWorkers =
        chainWorkers.subList(1, chainWorkers.size());
    SwingWorkerExecutor.RunAfter<Void> chainRunAfter;
    if (chainWorkers.size() > 1)
    {
        chainRunAfter = new SwingWorkerExecutor.RunAfter<Void>()
        {
            @Override
            public void run(Void value)
            {
                runChain(remainingWorkers, runAfter, runOnError);
            }
        };
    }
    else
    {
        chainRunAfter = runAfter;
    }

    currentWorker = chainWorkers.get(0);

    swingWorkerExecutor.execute(currentWorker, chainRunAfter, runOnError);
}

우리의 경우 Swingworkerexecutor는 실제로 이해하기 어려운 모든 것을 포함하기 때문에 이것은 매우 간단합니다.

public class DefaultSwingWorkerExecutor implements SwingWorkerExecutor
{
    @Override
    public <T> void execute(SwingWorker<T, ?> worker, RunAfter<T> after,
                            RunOnError onError)
    {
        worker.addPropertyChangeListener(
            new RunAfterHandler<T>(worker, after, onError));
        worker.execute();
    }

    private static class RunAfterHandler<T> implements PropertyChangeListener
    {
        private final SwingWorker<T, ?> worker;
        private final RunAfter<T> after;
        private final RunAfter<Throwable> onError;

        protected RunAfterHandler(SwingWorker<T, ?> worker, RunAfter<T> after,
                                  RunOnError onError)
        {
            this.worker = worker;
            this.after = after;
            this.onError = onError;
        }

        @Override
        public void propertyChange(PropertyChangeEvent evt)
        {
            if ("state".equals(evt.getPropertyName()) &&
                evt.getNewValue() == SwingWorker.StateValue.DONE)
            {
                if (worker.isCancelled())
                {
                    return;
                }

                try
                {
                    after.run(worker.get());
                }
                catch (InterruptedException e)
                {
                    Thread.currentThread().interrupt();
                }
                catch (ExecutionException e)
                {
                    onError.run(e);
                }
            }
        }
    }
}

여기에서 보지 않고 쓸 수있는 간단한 인터페이스가 있습니다.

우리의 실제 배포 Swingworkerexecutor는 기본값 대신 주입 된 ExecutorService를 사용하여 실행합니다 (단일 앱에 필요한 스레드 풀의 수를 줄입니다.) 조건 및 또한 단위 테스트로 논리를 대체 할 수 있습니다 (알다시피, 단일 스레드 인 경우 훨씬 간단합니다.) 알 수 있듯이 모든 스윙 워크 인에게 일반적으로 필요한 보일러 플레이트가 있습니다. 내부 done (), 따라서 그렇게하는 대신 done () 작업을 콜백으로 옮깁니다.

장점은 체인에서 여러 개의 스윙 워크를 실행하는 것과 같은 것들이 구현하기 쉽다는 것입니다.

두 프로세스를 순차적으로 수행하려면 전통적으로 다른 방법을 호출합니다 (!).

fillList();
doStuffToList();

또는 아마도 다음과 같은 것입니다.

doStuffToList(fillList());

한 번에 하나씩 처리하는 경우 두 개의 스레드를 BlockingQueue 사이. 여러 do-stufl 스레드를 사용하여 더 나아갈 수 있습니다.

AWT 이벤트 디스패치 스레드 (EDT)가 우려되는 한, 차단하지 않고 동작을 방출하고 나중에 알림을받습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top