многопоточность и файлы в java

223
04 февраля 2020, 02:00

Я пытаюсь создать программу, потоки которой считывали бы и изменяли файл. Все это обернул в самописную семафору, которая контролирует доступ к файлу. Но, к сожалению, в процессе работы программы я иногда получаю EOFException, хотя в теории такого быть не должно. Что я делаю не так? Вот класс семафоры и потоков, которые запускаются при запуске программы:

    package Test;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;

public class Client {
    private static int errors = 0;
    private ArrayList<Template> arrayList;
    private String filepath = System.getProperty("user.dir") + "\\src.txt";
    public class Semaphore{
        private int i = 0;
        public synchronized void take(){
            i++;
            while(i > 1){
                try{
                    wait();
                } catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
        public synchronized void release(){
            i = 0;
            this.notify();
        }
    }
    public ArrayList<Template> getTemplates(){
        ArrayList<Template> arrayList = new ArrayList<Template>();
        for(int i = 0; i < 2000; i++){
            Template template = new Template();
            template.id = i;
            arrayList.add(new Template());
        }
        for(Template template : arrayList){
            StringBuilder text = new StringBuilder("");
            for(int j = 0; j < 2000; j++){
                text.append(j);
            }
            template.text = text.toString();
        }
        return arrayList;
    }
    public class Worker extends Thread{
        private Semaphore semaphore;
        private int count;
        public Worker(int c,Semaphore semaphore){
            count = (c == 1 ? 1 : 0);
            this.semaphore = semaphore;
        }
        public void write(Template template){
            try{
                Path path = Paths.get(filepath);
                byte[] bytes = Files.readAllBytes(path);
                ByteArrayInputStream in = new ByteArrayInputStream(bytes);
                ObjectInputStream is = new ObjectInputStream(in);
                ArrayList<Template> arrayList =(ArrayList<Template>) is.readObject(); // Вот эта строка выкидывает EOFException
                arrayList.add(template);
                ByteArrayOutputStream out = new ByteArrayOutputStream();
                ObjectOutputStream os = new ObjectOutputStream(out);
                os.writeObject(arrayList);
                Files.write(path,out.toByteArray());
            } catch (Exception e){
                System.out.println("Thread - " + (count % 2) + " : " + count);
                e.printStackTrace();
            } finally {
                semaphore.release();
            }
        }
        public void run(){
            while(count < arrayList.size()){
                semaphore.take();
                write(arrayList.get(count));
                count+=2;
            }
        }
    }
    private void writeNewArray(){
        try{
            Path paths = Paths.get(filepath);
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            ObjectOutputStream os = new ObjectOutputStream(out);
            os.writeObject(new ArrayList<Template>());
            Files.write(paths,out.toByteArray());
        } catch (Exception e){
            e.printStackTrace();
            System.exit(0);
        }
    }
    private void run(){
        this.arrayList = getTemplates();
        Semaphore semaphore = new Semaphore();
        writeNewArray();
        new Worker(0,semaphore).start();
        new Worker(1,semaphore).start();
    }
    public static void main(String[] args) {
        new Client().run();
    }
}
Answer 1

Проблема в этом коде

    public synchronized void release(){
        i = 0;
        this.notify();
    }

Если два потока вызовут take то i = 2. Затем первый поток вызовет release и обнулит счетчик, а должен просто уменьшить.

Правильный код

    public synchronized void release(){
        i--;
        this.notifyAll();
    }

Также нужно исправить take

    public synchronized void take(){
        while(i > 0){
            try{
                wait();
            } catch (Exception e){
                e.printStackTrace();
            }
        }
        i++;
    }
READ ALSO
Не могу понять блок кода в реализации LinkedList

Не могу понять блок кода в реализации LinkedList

Дана реализация связанного списка:

252
javax.servlet.ServletException: UT010013

javax.servlet.ServletException: UT010013

Переношу проект со старого сервера (debian 7, wildfly 82

273
Node.js (telegraf). Непонятная ошибка в сценарии

Node.js (telegraf). Непонятная ошибка в сценарии

Выдает ошибку когда нажать Button ("USD-UAH») после нее Button ("EUR-UAH») показывает ошибку

228
Chart Js Число и день недели

Chart Js Число и день недели

Нужно сделать так

217