Já vou logo avisando que não quero que resolvam para mim o exercício, eheeh, gostaria apenas de algumas opniões, talvez um “norte”. Já pesquisei e pesquisei muuuito e não consigo resolver a bagaça, resolvi postar aqui também pq em minha pesquisa acabei encontrando informações que divergem frontalmente com as quais o professor nos passa. Passo a desecrever abaixo a descrição do problema, algumas observações em relação às restrições e, em seguida, o código, e, após este último, a descrição de minhas tentativas.
Modifique a implementação da classe AgenteConta utilizando somente travas explicitas de modo que, ao final da execução, suas quatro instâncias tenham o mesmo saldo (1.000.000,00). É proibido modifcar o método main() e é proibido também usar trava ou monitor global único para todas as threads. Também é probibido mudar a lógica da aplicação (i.e., cada instancia de AgenteConta deve continuar debitando das outras contas, creditando para si e, em seguida, transferindo uma unidade para cada uma das outras contas) e a sequência de operações realizadas no método run().
[color=darkblue] Considerações sobre as restrições:[/color]
Como o professor viu que ninguém estava conseguindo resultados resolveu afrouxar as restrições e disse que poderiamos fazer uma primeira versão quebrando uma ou outra restrição, como por exemplo usar monitores globais.
Sobre a divergencia com o que professor considera como travas explicitas
Segundo ele, travas explicitas são travas em que se usa synchronized/wait/sleep em blocos de codigos ou em métodos, em minha pesquisa encontrei exatamente o contrário, várias fontes dizem que estes são locks implícitos, que travas explícitas seriam quando instanciamos uma implementação da interface Lock. Normalmente, instancia-se ReentrantLock. O que me dizem?
[color=darkred]O Código original:[/color]
public class AgenteConta implements Runnable
{
private double saldo = 1000000.0;
private AgenteConta[] contas = new AgenteConta[ 3 ];
public AgenteConta( )
{
}
public AgenteConta( AgenteConta c1, AgenteConta c2, AgenteConta c3 )
{
contas[ 0 ] = c1;
contas[ 1 ] = c2;
contas[ 2 ] = c3;
}
public void debitar( double valor )
{
if ( valor <= saldo )
{
saldo -= valor;
}
else
{
System.out.println( "Saldo Insuficiente" );
}
}
public void creditar( double valor )
{
saldo += valor;
}
public void transferir( AgenteConta c, double quantia )
{
c.saldo = c.saldo - quantia;
this.saldo += quantia;
}
public void run( )
{
for ( long i = 0; i < 1000000; i++ )
{
contas[ 0 ].debitar( 1 );
contas[ 1 ].debitar( 1 );
contas[ 2 ].debitar( 1 );
this.creditar( 3 );
this.transferir( contas[ 0 ], 1 );
this.transferir( contas[ 1 ], 1 );
this.transferir( contas[ 2 ], 1 );
}
}
public static void main( String[] args )
{
long t = System.currentTimeMillis( );
AgenteConta c1 = new AgenteConta( );
AgenteConta c2 = new AgenteConta( );
AgenteConta c3 = new AgenteConta( );
AgenteConta c4 = new AgenteConta( c1, c2, c3 );
c1.contas = new AgenteConta[] { c2, c3, c4 };
c2.contas = new AgenteConta[] { c1, c3, c4 };
c3.contas = new AgenteConta[] { c1, c2, c4 };
Thread t1 = new Thread( c1 );
Thread t2 = new Thread( c2 );
Thread t3 = new Thread( c3 );
Thread t4 = new Thread( c4 );
t1.start( );
t2.start( );
t3.start( );
t4.start( );
try
{
t1.join( );
t2.join( );
t3.join( );
t4.join( );
}
catch ( InterruptedException e )
{
System.out.println( "Erro" + e.getMessage( ) );
}
System.out.println( " C1: " + c1.saldo + " C2: " + c2.saldo + " C3: "
+ c3.saldo + " C4: " + c4.saldo );
System.out.println( " Tempo: " + (System.currentTimeMillis( ) - t) );
}
}
O que já tentei:
- Sincronizar o bloco principal dentro de run(), da seguinte maneira:
Também tentei sem o sinchronized interno
[code] public void run() {
for (long i = 0; i < 1000000; i++) {
synchronized (contas) {
contas[0].debitar(1);
contas[1].debitar(1);
contas[2].debitar(1);
synchronized (this) {
this.creditar(3);
this.transferir(contas[0], 1);
this.transferir(contas[1], 1);
this.transferir(contas[2], 1);
}
}
}
}[/code]
-
Sincronizando junto os metodos debitar, creditar e transferir.
-
Também tentei criar uma variável (membro da classe AgenteConta) para monitorar um lock e 2 metodos sincronizados, um para setar esta varivel como locked e outra para liberar, alterando também o métod run() conforme segue:
[code]
public synchronized void lock(){
isLocked = true;
}
public synchronized void unlock(){
isLocked = false;
notify();
}
public void run() {
lock();
System.out.println(Thread.currentThread().getName());
if (! isLocked) {
for (long i = 0; i < 5; i++) {
System.out.println(i);
contas[0].debitar(1);
contas[1].debitar(1);
contas[2].debitar(1);
this.creditar(3);
this.transferir(contas[0], 1);
this.transferir(contas[1], 1);
this.transferir(contas[2], 1);
}
unlock();
}
else {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}[/code]
Tudo sem sucesso. :-/