Given:
public static synchronized void main( String[] args ) throws InterruptedException {
Thread t = new Thread();
t.start();
System.out.print( "X" );
t.wait( 10000 );
System.out.print( "Y" );
}
What is the result of this code?
A. It print X and exits
B. It print Y and never exits
C. It print XY and exits almost immeditately
D. It print XY width 10-second delay between X and Y
E. It print XY width 10000-second delay between X and Y
F. The code does not compile
G. An exception is thrown at runtime
Antes de explicar esse problema, vamos diferenciar algumas coisas:
a) O método wait() é um método de um objeto, não de uma thread. Ele faz com que a thread atual pare, até que outra thread chame o método notify() sobre o mesmo objeto.
b) Para toda thread criada em Runtime, teremos a thread em si (a linha de execução) e um objeto, que representa essa thread, e é filho da classe Thread. Note que a thread e o objeto que a representa são coisas diferentes.
c) Para que os métodos wait() e notify() possam ser chamados, o objeto tem que ser o monitor. Você faz isso colocando ele como parâmetro de um bloco synchronized.
Pois bem, nesse exemplo, criamos um objeto do tipo Thread, e o chamamos de t. Depois, usamos ele para disparar outra thread. A outra thread não tem qualquer relevância para a analise do problema. Ela provavelmente vai iniciar e morrer logo em seguida, já que nem runnable tem.
O que interessa mesmo é o que acontece na main thread. Ela tem um método main sincronizado. Isso significa que o monitor está na ClassDoMain.class e não no objeto t. E é no objeto t que o wait está sendo chamado. Quando o método wait() for invocado a exceção de que o objeto t não é um monitor será lançada.
A correção para esse código ficaria:
Given:
public static void main( String[] args ) throws InterruptedException {
Thread t = new Thread();
t.start();
System.out.print( "X" );
synchronized (t) {
t.wait( 10000 );
}
System.out.print( "Y" );
}
Note que t poderia pertencer a qualquer outra classe, como String. Pouco importa dele ser um objeto que descreve uma thread ou não.
Toda sincronização elege como monitor um objeto. E é nesse objeto que precisamos chamar o método wait.
Em outros objetos, o comando irá lançar a exceção, indicando que o objeto não é o monitor.
Por exemplo, abaixo um código que usa “lock” como monitor:
[code]
public class Classe {
private int[0] lock = new int[0]; //Um objeto qualquer
public void metodo() {
synchronized (lock) { //lock é o monitor
lock.wait(1000);
}
}
}[/code]
O que acontece quando declaramos um método como synchronized?
Se o método não for estático, o objeto do lock é o this. Portanto, os dois métodos abaixo tem sincronização equivalente:
public class Classe {
public void metodo1() {
synchronized (this) { //
wait(1000);
}
}
public synchronized void metodo2() {
wait(1000);
}
}
Logo, ambos os métodos são mutuamente excludentes.
E se o método for static? Nesse caso, a sincronização acontecerá sobre o class:
public class Classe {
public static void metodo1() {
synchronized (Classe.class) { //
wait(1000);
}
}
public synchronized static void metodo2() {
wait(1000);
}
}
No código que você passou, a sincronização do método main está ocorrendo num class. É nesse objeto de lock que a main thread está. Entretanto, ele está tentando chamar o wait do objeto t. Veja, aquele wait não tem qualquer efeito sobre a thread que o objeto t criou, ele atua sobre a main thread.
Vamos reescrever aquele código numa versão equivalente, usando a sintaxe do monitor explícito:
public class Classe {
public static void main( String[] args ) throws InterruptedException {
synchronized (Classe.class) { //O monitor é classe.class
Thread t = new Thread();
t.start();
System.out.print( "X" );
t.wait( 10000 ); //Ops! Estamos chamando wait em t, não em Classe.class!
System.out.print( "Y" );
}
}
}
saíram: wait/notify, serialização, java beans, varargs, e algumas APIs de java.io[/quote]
Nosso, então esta bem mais fácil, mais pena que pelo SAI ainda esta no modelo antigo.[/quote]
pois é, eu confirmo :evil:
eu fui fazer a prova sem saber disso, e na semana anterior eu praticamente me matei de ver thread, serialização, varags e IO. A unica coisa que eu tinha deichado de lado era o java beans … quase me fo** :x