threads - Duvida sobre Thread
Perguntas � threads � Duvida sobre Thread
Duvida sobre Thread
Fala galera, to com uma dúvida que está me matando, to com uma atividade da faculdade onde eu tenho que gravar alguns dados de uns objetos no arquivo, mas a gravação desses dados tem que ser feito através de uma thread, a classe tem que implementar runnable, fiquei sem saber como iria passar o objeto que vai ser gravado pra dentro da classe que será uma thread e se encarregará de gravar no arquivo, então, eu fiz a seguinte situação, gostaria de saber de vocês mais experiente se isso é correto de se fazer ou existe uma forma melhor de fazer isso.
Estou criando um atributo Object.
Quando instanciado a classe que implementa thread espera que seja passado um objeto no seu construtor.
public class Log implements Runnable{
public Log(Object o) {
inserir(getObject());
private static void inserir(Object o)  throws IOException, IllegalArgumentException, IllegalAccessException {
FileOutputStream outputStream  = new FileOutputStream(f);
oos.writeObject(pegaDadosLog(o));
System.out.println("Gravou");
private static String pegaDadosLog(Object o) throws IllegalArgumentException, IllegalAccessException{
Field [] fields = o.getClass().getDeclaredFields();
for (Field campo : fields) {
if(campo.isAnnotationPresent(br.ucb.talp.simulado.ennotations.Log.class)){
sb.append(campo.getName()+" "+campo.get(o));
A chamada está da seguinte forma
public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException, IOException {
Urna u = View.lerUmaUrna();
new Thread(new Log(u)).start();
}while(Leitora.lerInt("Deseja informar mais uma urna? 1 - sim 2 nao")!= 2);
Desde já agradeço todo aqueles que me ajudar.
editado 26 de set de 2015
Vc tem um problema ai. O teu método "inserir" não está como "sincronized". Dessa forma as threads vão executar de forma não sincronizada. Isso pode acarretar em uma sobrescrever o conteúdo da outra. o Correto seria:
private static syncronized void inserir(Object o)  throws IOException, IllegalArgumentException, IllegalAccessException {
wait(); /* Agurdar liberação objeto por outras threads */
notifyAll(); /* Notifica outras threads que terminou de executar. A partir daqui um thread lock a transação enquanto as outras aguardam. Esse ciclo se repete até terminar todas as threads  */
Você não postou como está fazendo a chamada das threads. Poderia postar também?
Coloquei onde faço a chamada, da uma olha la por favor :)
— Kleiton Batista 26 de set de 2015
Para cada urna será gerado um arquivo diferente? Ou todas as urnas serão salvas em um único arquivo?
— Emir Marques 26 de set de 2015
Deveria ser no mesmo arquivo, nesse meu caso só está salvando a última urna
Certo, então é devido ao que falei, vc não está fazendo um semáforo entre as threads, uma está matando a alteração da outra. Tente efetuar o ajuste que falei
Eu coloquei o syncronized, porém o método wait(); e notfyAll (); não são reconhecidos dentro deste metodos
Ele está apagando o arquivo porque esse é o comportamento padrão do FileOutputStream. Não tem nada a ver com threads. Basta incluir o parâmetro true no construtor. Esse parâmetro indica que você quer fazer append no arquivo: http://docs.oracle.com/javase/7/docs/api/java/io/FileOutputStream.html#FileOutputStream(java.io.File,%20boolean)
— ViniGodoy 26 de set de 2015
Melhor do que o synchronized, seria usar uma fila de mensagens entre as duas threads. O java tem para isso uma classe chamada LinkedBlockingQueue, justamente para isso.
Sua classe então só fica observando se algo novo entrou na fila para ser logado. Quando houver, remove o objeto da fila e faz o log.
public class Log implements Runnable {
private BlockingQueue<Object> fila = new LinkedBlockingQueue<>();
public Log() {}
//Enquanto não for chamado interrupt na thread
//Tenta retirar da fila e loga o que retirar
Object proximo = fila.take();
inserir(proximo);
public void gravar(Object o) {
//Insere um objeto na fila
fila.offer(o);
private void inserir(Object o)  throws Exception {
try (PrintWriter out = new PrintWriter(new FileOutputStream(new File("log.txt"), true))) {
out.println(pegaDadosLog(o));
private String pegaDadosLog(Object o) throws IllegalArgumentException, IllegalAccessException{
sb.append(campo.getName()).append(" ").append(campo.get(o));
Isso é chamado de padrão do Produtor/Consumidor. Onde uma Thread produz conteúdo (no caso, os objetos) e outra os consome para realizar uma operação (loga-los no disco). Para usar você só faria:
Thread.start(log);
log.gravar(seuObjeto1);
log.gravar(seuObjeto2);
Também corrigi outros pequenos erros. Por exemplo, apesar de criar um StringBuilder no loop, você ainda usava concatenação no método append, o que fazia seu StringBuilder perder todo o sentido. No lugar do ObjectOutputStream, use um PrintWriter, já que você já estava serializando o objeto numa String.
Não estou com uma IDE, por isso não testei o código. Mas se tiver alguma dúvida ao entende-lo é só postar. Em boa parte das vezes, separar a aplicação em threads que fazem coisas distintas e se comunicam por filas é uma estratégia muito preferível a tentar sincronizar coisas na mão.
Outra coisa: Threads e métodos static não combinam. Métodos statics tendem a enfileirar threads muito mais do que deveriam ser enfileiradas. Esse é mais um motivo para evitar ao máximo métodos estáticos.