(USAR SYNCHRONIZED?)The process cannot access the file because it is being used by another process

4 respostas
W

Oi gente, estou com o seguinte problema:
Tenho um método de gravação de log que é acessado por um versionador. De vez em quando surge a seguinte mensagem de erro no console do versionador:

C:\Versionador\Logs\nomeDoArquivo.log(The process cannot access the file because it is being used by another process)

Isso provavelmente acontece quando outro usuário de outra console faz um procedimento que acessa esse mesmo arquivo de log e coincide de estar no meio de uma gravação.
Gostaria de saber se tornando esse método sincronizado resolveria o problema, pois sendo sincronizado, o método seria acessado somente após quem o estiver acessando terminar a execução.

Mas, quando outro processo tentar acessá-lo, ele ficará aguardando o término da execução para ser liberado o acesso ao método sincronizado?
Eu sei que poderia fazer os testes, mas gostaria da opinião dos mais experientes em Java e se essa é a melhor solução para esse caso.

Segue o método de gravação.

private int GravaLog(Date data, String data) throws Exception{ int retorno = 0; try { File install = new File("C:\\Versionador\\Logs\\nomeDoArquivo" + data + ".log"); BufferedWriter installData = new BufferedWriter(new FileWriter(install,true)); installData.write("\r\n"); installData.write("Dados a serem gravados"); installData.write("Dados a serem gravados"); installData.close(); } catch(Exception err) { retorno = 0; System.err.println(err.getMessage()); } return retorno; }

Agradeço a ajuda.

4 Respostas

L

Se o outro processo for outra instancia da sua aplicação rodando em outra maquina, então não resolveria.

Achei isso que pode te ajudar:

public static void main(String arsg[]) throws IOException,
			InterruptedException {
		RandomAccessFile raf = new RandomAccessFile("teste.log", "rw");
		FileChannel channel = raf.getChannel();
		System.out.println("trying lock!!!");
		FileLock lock = channel.lock();
		try {
			System.out.println("Got lock!!!");
			File install = new File("teste.log");
			BufferedWriter installData = new BufferedWriter(new FileWriter(
					install, true));
			installData.write("\r\n ");
			installData.write("Dados a serem gravados ");
			installData.write("Dados a serem gravados ");
			System.out.println("wait");
			Thread.sleep(20000);
			installData.close();
			System.out.println("ok");
		} finally {
			lock.release();
		}
	}

http://java.sun.com/developer/JDCTechTips/2002/tt0924.html

W

Cara eu tentei fazer o seguinte:

private int GravaLog(Date data, String data) throws Exception{ int retorno = 0; RandomAccessFile raf = new RandomAccessFile("C:\\Versionador\\Logs\\nomeDoArquivo" + data + ".log", "rw"); FileChannel channel = raf.getChannel(); System.err.println("Trying lock!!!"); FileLock lock = channel.lock(); try { File install = new File("C:\\Versionador\\Logs\\nomeDoArquivo" + data + ".log"); BufferedWriter installData = new BufferedWriter(new FileWriter(install,true)); installData.write("\r\n"); installData.write("Dados a serem gravados"); installData.write("Dados a serem gravados"); for(int i = 0; i < 100; i++){ System.out.println(i + "seg."); Thread.sleep(1000); } installData.close(); } catch(Exception err) { retorno = 0; System.err.println(err.getMessage()); } finally{ lock.release(); System.err.println("File unloked!!!"); } return retorno; }

Executei um processo da minha máquina, que acessa esse método de gravação de logs e de outra máquina executei outro processo que chama esse mesmo método. Então tenho a mensagem na console da ferramenta:

The process cannot access the file because another process has locked a portion of the file .
File unloked!!! . (mensagem que coloquei no código)
The process cannot access the file because it is being used by another process.

Continua o mesmo problema. Eu preciso que quando outro processo acessar o arquivo de log que está sendo usado fique aguardando este arquivo ser liberado pelo método e então continuar a execução.
Teria outra idéia? obrigado.

L

Ai eu não sei

tenho que conseguir simular isso aqui e não consegui.

Executei esse exato programa em dois consoles ao mesmo tempo e obtive o seguinte resultado:

public static void main(String[] args) throws Exception {
		RandomAccessFile raf = new RandomAccessFile("teste.log", "rw");
		FileChannel channel = raf.getChannel();
		System.out.println(System.currentTimeMillis() + " - trying lock!!!");
		FileLock lock = channel.lock();
		try {
			System.out.println(System.currentTimeMillis() + " - got lock!!!");
			File install = new File("teste.log");
			BufferedWriter installData = new BufferedWriter(new FileWriter(
					install, true));
			installData.write("Blehhhh");
			System.out.println(System.currentTimeMillis() + " - waiting");
			Thread.sleep(20000);
			installData.close();
			System.out.println(System.currentTimeMillis() + " - done");
		} finally {
			lock.release();
		}
		System.out.println(System.currentTimeMillis() + " - unlock");
	}

Primeira execução

1235043762232 - trying lock!!!
1235043762233 - got lock!!!
1235043762234 - waiting
1235043782235 - done
1235043782236 - unlock

Segunda execução

1235043765318 - trying lock!!!
1235043782234 - got lock!!!
1235043782235 - waiting
1235043802236 - done
1235043802236 - unlock

Repare que pelos horários eles rodaram junto.

Tem como vc fazer um pequeno main que simule o problema?! ai posso tentar ver

W

Cara, eu executei seu programa em 2 terminais do DOS e veja a saída que deu em cada um dos terminais:
Eu copiei e colei seu código e só modifiquei o nome do arquivo teste.log para o nome e caminho na minha máquina. Não entendi.

primeiro terminal

1235053126155 - trying lock!!!

1235053126202 - got lock!!!

1235053126202 - waiting

Exception in thread main java.io.IOException: O processo nÒo pode acessar o arquivo porque outro processo bloqueou parte do

arquivo

at java.io.FileOutputStream.writeBytes(Native Method)

at java.io.FileOutputStream.write(Unknown Source)

at sun.nio.cs.StreamEncoder.writeBytes(Unknown Source)

at sun.nio.cs.StreamEncoder.implClose(Unknown Source)

at sun.nio.cs.StreamEncoder.close(Unknown Source)

at java.io.OutputStreamWriter.close(Unknown Source)

at java.io.BufferedWriter.close(Unknown Source)

at TesteFileLock.main(TesteFileLock.java:29)
segundo terminal

1235053126280 - trying lock!!!

1235053146200 - got lock!!!

1235053146200 - waiting

Exception in thread main java.io.IOException: O processo nÒo pode acessar o arquivo porque outro processo bloqueou parte do

arquivo

at java.io.FileOutputStream.writeBytes(Native Method)

at java.io.FileOutputStream.write(Unknown Source)

at sun.nio.cs.StreamEncoder.writeBytes(Unknown Source)

at sun.nio.cs.StreamEncoder.implClose(Unknown Source)

at sun.nio.cs.StreamEncoder.close(Unknown Source)

at java.io.OutputStreamWriter.close(Unknown Source)

at java.io.BufferedWriter.close(Unknown Source)

at TesteFileLock.main(TesteFileLock.java:29)

Mas mesmo que funcionasse da forma que vc executou eu acho que não serviria pro meu caso, pois eu preciso que uma execução vá até o final e grave os dados no arquivo e se outro processo acessar o arquivo enquanto outro processo estiver gravando, ele deve aguardar e quando o arquivo for liberado, continuar com a execução. Pois os dados de um log devem ser gravados no final dos dados da última execução.
E pelo que entendi, na sua execução, um processo começaria a gravar e daria uma pausa e o outro processo continuaria. Dessa maneira, os dados do log ficariam misturados, ou estou enganado?

A parte com problema é esse arquivo de gravação de log mesmo e não daria pra eu fazer um main que simulasse a chamada deste método.
Mas resumindo, um processo chama o .jar que executa uma série de passos e chama esse método e outro processo poderia concomitantemente chamar esse mesmo .jar que ao chegar nesse método de gravação de log, dá o erro que postei no tópico.

Bom, de qualquer maneira agradeço sua atenção.

Criado 17 de fevereiro de 2009
Ultima resposta 19 de fev. de 2009
Respostas 4
Participantes 2