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!