Multithreading: Vários Objetos Lock

0 respostas
KelvinAzevedo

Estou estudando pelo livro Java Como Programar, e ainda não estou confiante em relação aos bloqueios. Gosto de entender as coisas modificando os exemplos do livro, e esse em particular eu modifiquei bastante, e aprendi bastante com isso.
Ele faz três JPanels que ficam com letras mudando aleatóriamente com o tempo, com a opção de bloqueá-los, impedindo a mudança da letra, através de checkbox.
Eu fiz uma última modificação nesse programa, transformando um objeto Lock em três, a acabando com as "Condition"s. Gostaria de saber se há alguma boa razão para a forma encontrada no livro, que para mim parece bastante extensa e confusa.

Vou colocar aqui o exemplo do livro na íntegra, e também o meu código mais abaixo, para vocês rodarem se quiserem, e com comentários em todas as modificações.
Código do Exemplo no Livro:

import java.awt.Color;
import java.util.Random;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;

public class RunnableObject implements Runnable{
    
    private static Random generator = new Random();
    private Lock lockObject;
    private Condition suspend;
    private boolean suspended = false;
    private JLabel output;
    
    public RunnableObject( Lock theLock, JLabel label){
        lockObject = theLock;
        suspend = lockObject.newCondition();
        output = label;
    }
    
    @Override
    public void run() {
        final String threadName = Thread.currentThread().getName();
        
        while(true){
            try{
                Thread.sleep( generator.nextInt( 1000 ));
                lockObject.lock();
                try{
                    while(suspended){
                        suspend.await();
                    }
                }
                finally{
                    lockObject.unlock();
                }
            }
            catch (InterruptedException e){
                e.printStackTrace();
            }
            finally{
                lockObject.unlock();
            }
            
            SwingUtilities.invokeLater(
                    new Runnable(){
                        public void run(){
                            char displayChar = (char)( generator.nextInt(26) + 65 );
                            output.setText( threadName + ": " + displayChar );
                        }
                    }
            );
        }
    }
    
    public void toogle(){
        suspended = !suspended;
        output.setBackground( suspended ? Color.RED : Color.GREEN );
        lockObject.lock();
        try{
            if( !suspended ){
                suspend.signal();
            }
        }
        finally{
            lockObject.unlock();
        }
    }
}
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class RandomCharacters extends JFrame implements ActionListener{
    
    private final static int SIZE = 3;
    private JCheckBox checkboxes[];
    private Lock lockObject = new ReentrantLock( true );
    private RunnableObject[] randomCharacters = new RunnableObject[ SIZE ];
    
    public RandomCharacters(){
        checkboxes = new JCheckBox[ SIZE ];
        setLayout( new GridLayout( SIZE, 2, 5, 5 ));
        
        ExecutorService runner = Executors.newFixedThreadPool( SIZE );
        
        for(int count = 0; count < SIZE; count++ ){
            JLabel outputJLabel = new JLabel();
            outputJLabel.setBackground( Color.GREEN );
            outputJLabel.setOpaque( true );
            add( outputJLabel );
            
            checkboxes[count] = new JCheckBox( "Suspended" );
            
            checkboxes[count].addActionListener(this);
            add( checkboxes[count] );
            
            randomCharacters[count] =  new RunnableObject( lockObject, outputJLabel );
            runner.execute( randomCharacters[count] );
        }
        
        setSize(275, 90);
        setVisible( true );
        
        runner.shutdown();
    }
    
    public static void main(String[] args) {
        RandomCharacters application = new RandomCharacters();
        application.setDefaultCloseOperation( EXIT_ON_CLOSE );
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        for( int count = 0; count < checkboxes.length; count++ ){
            if( e.getSource() == checkboxes[count] ){
                randomCharacters[ count ].toogle();
            }
        }
    }
}

Minhas modificações:

import java.awt.Color;
import java.util.Random;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;

public class RunnableObject implements Runnable{
    
    private static Random generator = new Random();
    private Lock lockObject;
    private Condition suspend;
    private boolean suspended = false;
    private JLabel output;
    
    public RunnableObject( Lock theLock, JLabel label){
        lockObject = theLock;
        suspend = lockObject.newCondition();
        output = label;
    }
    
    @Override
    public void run() {
        final String threadName = Thread.currentThread().getName();
        
        while(true){
            try{
                Thread.sleep( generator.nextInt( 1000 ));
                lockObject.lock();

                // MUITAS LINHAS REMOVIDAS AQUI
            }
            catch (InterruptedException e){
                e.printStackTrace();
            }
            finally{
                lockObject.unlock();
            }
            
            SwingUtilities.invokeLater(
                    new Runnable(){
                        public void run(){
                            char displayChar = (char)( generator.nextInt(26) + 65 );
                            output.setText( threadName + ": " + displayChar );
                        }
                    }
            );
        }
    }
    public void toogle(){
        suspended = !suspended;
        output.setBackground( suspended ? Color.RED : Color.GREEN );
        
       // Removido o Lock aqui, e agora o Lock está equivalente ao boolean suspended

        if( !suspended ){
            lockObject.unlock();
        }
        else{
            lockObject.lock();
        }
    }
}
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class RandomCharacters extends JFrame implements ActionListener{
    
    private final static int SIZE = 3;
    private JCheckBox checkboxes[];
    private RunnableObject[] randomCharacters = new RunnableObject[ SIZE ];

    // Removi a variável Lock daqui
    
    public RandomCharacters(){
        checkboxes = new JCheckBox[ SIZE ];
        setLayout( new GridLayout( SIZE, 2, 5, 5 ));
        
        ExecutorService runner = Executors.newFixedThreadPool( SIZE );
        
        for(int count = 0; count < SIZE; count++ ){
            JLabel outputJLabel = new JLabel();
            outputJLabel.setBackground( Color.GREEN );
            outputJLabel.setOpaque( true );
            add( outputJLabel );
            
            checkboxes[count] = new JCheckBox( "Suspended" );
            
            checkboxes[count].addActionListener(this);
            add( checkboxes[count] );
            
            randomCharacters[count] =  new RunnableObject( new ReentrantLock( true ), outputJLabel ); // Aqui cada objeto RunnableObject recebe sua própria instância de Lock
            runner.execute( randomCharacters[count] );
        }
        
        setSize(275, 90);
        setVisible( true );
        
        runner.shutdown();
    }
    
    public static void main(String[] args) {
        RandomCharacters application = new RandomCharacters();
        
        application.setDefaultCloseOperation( EXIT_ON_CLOSE );
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        for( int count = 0; count < checkboxes.length; count++ ){
            if( e.getSource() == checkboxes[count] ){
                randomCharacters[ count ].toogle();
            }
        }
    }
}

Obrigado!

Criado 2 de julho de 2013
Respostas 0
Participantes 1