Pergunta

Eu tenho uma aplicação swing que armazena uma lista de objetos. Quando os usuários clica em um botão,

Eu quero executar duas operações em cada objeto na lista, e, em seguida, uma vez que seja completa, o gráfico dos resultados em um JPanel. Eu tenho tentado SwingWorker, mobilizável & Runnable para fazer o processamento, mas não importa o que eu faça, enquanto o processamento da lista (que pode levar até alguns minutos, como é IO bound), a GUI é trancado.

Eu tenho um sentimento que é provavelmente a maneira que eu estou chamando os fios ou algo assim, ou poderia ser a ver com a função de gráficos? Isso não é enfiada, pois é muito rápido.

Eu tenho que fazer as duas etapas de processamento, a fim também, então qual é a melhor maneira de garantir o segundo esperou no primeiro? Eu usei join (), e depois

while(x.isAlive())  
{  
        Thread.sleep(1000);  
}

para tentar garantir isso, mas estou preocupado com isso poderia ser a causa do meu problema também.

Eu tenho procurado em todos os lugares para algumas indicações, mas desde que eu não consigo encontrar nenhuma eu tenho certeza que eu estou fazendo algo estúpido aqui.

Foi útil?

Solução

O problema é que a sua tarefa de longa duração está a bloquear o fio que mantém o GUI responsivo.

O que você precisa fazer é colocar a tarefa de longa duração em outro segmento.

Algumas formas comuns de fazer isto está usando temporizadores ou um SwingWorker .

O Java tutoriais têm muita informação sobre estas coisas em sua lição de concorrência.

Para se certificar de chegada da primeira tarefa antes da segunda, basta colocar os dois no mesmo segmento. Dessa forma, você não terá que se preocupar em manter duas linhas diferentes cronometrado corretamente.

Aqui está um exemplo de implementação de um SwingWorkerFor seu caso:

public class YourTaskSwingWorkerSwingWorker extends SwingWorker<List<Object>, Void> {
    private List<Object> list
    public YourClassSwingWorker(List<Object> theOriginalList){
        list = theOriginalList;
    }

    @Override
    public List<Object> doInBackground() {
        // Do the first opperation on the list
        // Do the second opperation on the list

        return list;
    }

    @Override
    public void done() {
        // Update the GUI with the updated list.
    }
}

Para usar esse código, quando o evento para modificar a lista é disparado, crie um novo SwingWorker e dizer-lhe para começar.

Outras dicas

Você não está retornando o fio balanço corretamente. Eu sei que você está usando exigível / executável, mas eu estou supondo que você não está fazendo certo (embora você não fez código postal suficiente para saber com certeza).

A estrutura básica seria:

swingMethod() { // Okay, this is a button callback, we now own the swing thread
    Thread t=new Thread(new ActuallyDoStuff());
    t.start();
}

public class ActuallyDoStuff() implements Runnable {
    public void run() {
        // this is where you actually do the work
    }
}

Este é apenas fora do topo da minha cabeça, mas eu estou supondo que você quer não está fazendo a Thread.Start e são em vez de chamar o método de execução diretamente, ou você está fazendo outra coisa no primeiro método que os bloqueios -lo (como Thread.Join). Nenhuma delas iria liberar o segmento de swing. O primeiro método deve retornar rapidamente, o método run () pode demorar tanto tempo como ele quer.

Se você está fazendo um Thread.Join no primeiro método, em seguida, o fio não está sendo devolvida ao sistema!

Edit: (Segunda edição na verdade) Eu acho que para falar com o problema que você está realmente sentindo - você pode querer pensar mais em termos de um sistema modelo / view / controller. O código que você está escrevendo é o controlador (a vista é geralmente considerado como sendo os componentes na tela - view / controller são geralmente muito fortemente ligada).

Quando o controlador recebe o evento, ele deve passar o trabalho fora de seu modelo. A vista é, em seguida, fora do quadro. Não espera para o modelo, é apenas feito.

Quando o seu modelo é acabado, ele precisa, em seguida, dizer ao controlador para fazer outra coisa. Ele faz isso através de um dos métodos de invocar. Isso transfere o controle de volta para o controlador e você ir em sua maneira alegre. Se você pensar sobre isso dessa forma, separando o controle e deliberadamente passá-lo para trás e não se sente tão volumoso, e é realmente muito comum para fazê-lo desta forma.

Parece que o problema pode ser que você está esperando nas roscas ao fim de dentro do segmento GUI. Seu segmento GUI não deve esperar sobre esses tópicos, em vez disso você deve ter os segmentos de trabalho invocar algum método no thread GUI que define um sinalizador. Quando ambos os sinalizadores são definidos então você sabe ambos os tópicos terminou e você pode fazer o gráfico.

eu realmente não posso falar com o modelo de segmentação swing, mas:

Eu tenho que fazer as duas etapas de processamento, a fim também, então qual é a melhor maneira de garantir o segundo esperou no primeiro?

Para este tipo de funcionalidade, eu sugiro que você criar dois segmentos de trabalho e incorporar um corretor JMS. Entregar o trabalho para os dois tópicos, passando mensagens em filas JMS que leram. Seu segmento GUI é livre para examinar as filas para determinar quando o trabalho está acontecendo e representam o ponto da situação na sua interface do usuário.

A solução para o meu problema era uma mistura de jjnguy e respostas de Bill K, então muito obrigado para que os rapazes. Eu precisava usar tópicos dentro de um SwingWorker assim:

public class Worker extends SwingWorker<Void, Void>   
{  
    private List<Object> list;  
    public YourClassSwingWorker(List<Object> theOriginalList){  
        list = theOriginalList;  
    }

    @Override
    public List<Object> doInBackground() {
        Thread t = new Thread(new ProcessorThread(list));  
        t.start();
    }

    @Override
    public void done() {
        // draw graph on GUI
    }
}  
class ProcessorThread implements Runnable {  
    //do lots of IO stuff  
    Thread t2 = new Thread(new SecondProcess());
    t2.start();  
}

Isso fez com certeza todo o trabalho estava sendo feito por segmentos de trabalho longe da GUI, e também garantir que o próprio SwingWorker não estava fazendo todo o trabalho, o que poderia ter sido um problema.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top