Синхронизация по файлу Java

233
27 августа 2018, 06:20

Подскажите пожалуйста, как сделать, чтобы потоки синхронизировались по файлу "fileWithAnAdress.txt"

public class Main {
    public static void main(String[] args) {
        boolean delete1 = (new File("fileWithoutGarbage.txt")).delete();
        Thread thread = new Thread(new CreateFileService());
        thread.start();
        Thread thread1 = new Thread(new ReadFileService());
        thread1.start();
    }
}
public class CreateFileService implements Runnable {
    @Override
    public void run() {
       List<String> list = new ArrayList<>();
        list.add("'С:\\WebServers\\home\\testsite\\www\\myfile1.txt'");
        list.add("'С:\\WebServers\\home\\testsite\\www\\myfile2.txt'");
        list.add("'С:\\WebServers\\home\\testsite\\www\\myfile3.txt'");
        list.add("'С:\\WebServers\\home\\testsite\\www\\myfile4.txt'");
        try {
            BufferedWriter bw = new BufferedWriter(new FileWriter("fileWithAnAdress.txt"));
            for (String s : list) {
                bw.write(s);
                bw.write(System.lineSeparator());
            }
            bw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
public class ReadFileService implements Runnable {
    @Override
    public void run() {
        List<String> lines = new ArrayList<>();
        List<String> newLines = new ArrayList<>();
        try {
            BufferedReader br = new BufferedReader(new FileReader("fileWithAnAdress.txt"));
            String line;
            while ((line = br.readLine()) != null) {
                lines.add(line);
            }
            System.out.println(lines);
            for (String s : lines) {
                String newString = s.substring(s.lastIndexOf('\\') + 1, s.lastIndexOf('.'));
                newLines.add(newString);
            }
            System.out.println(newLines);
        } catch (IOException e) {
            e.printStackTrace();
        }
        try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("fileWithoutGarbage.txt"))) {
            for (String newLine : newLines) {
                bufferedWriter.write(newLine);
                bufferedWriter.write(System.lineSeparator());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        File file = new File("fileWithoutGarbage.txt");
        System.out.println(file.length() + " byte");
    }
}
Answer 1

Непонятно зачем вам потоки, если вы запускаете их последовательно, но способов решить вашу задачу множество. Самый простой - дождаться завершения первого потока и потом запустить второй:

public static void main(String[] args) {
    boolean delete1 = (new File("fileWithoutGarbage.txt")).delete();
    Thread thread = new Thread(new CreateFileService());
    thread.start();
    thread.join();
    Thread thread1 = new Thread(new ReadFileService());
    thread1.start();
}

Обычно, когда порядок выполнения потоков роли не играет, можно использовать синхронизацию по общему ресурсу:

public class Main {
    public static void main(String[] args) {
        File file = new File("fileWithoutGarbage.txt");
        boolean delete1 = (file).delete();
        Thread thread = new Thread(new CreateFileService(file));
        thread.start();
        Thread thread1 = new Thread(new ReadFileService(file));
        thread1.start();
    }
}
public abstract class FileServices implements Runnable {
    protected File file;
    protected setFile(File file) {
        this.file = file;
    }
}
public class CreateFileService extends FileService {
    public CreateFileService(File file) {
        setFile(file);
    }
    @Override
    public void run() {
       synchronized(file) {
           ...
       }
    }
}
public class ReadFileService extends FileService {
    public ReadFileService(File file) {
        setFile(file);
    }
    @Override
    public void run() {
       synchronized(file) {
           ...
       }
    }
}

Но нет гарантии, что thread1 не начнёт выполняться раньше thread, поэтому в вашем случае этот способ не подходит. Придётся использовать какой-нибудь примитив синхронизации. Логика вашего кода - последовательность действий, разбитая на упорядоченные фазы - больше располагает к Phaser, но она настолько примитивна, что подойдёт и CountDownLatch:

public class Main {
    public static void main(String[] args) {
        boolean delete1 = (new File("fileWithoutGarbage.txt")).delete();
        CountDownLatch latch = new CountDownLatch(1);
        Thread thread = new Thread(new CreateFileService(latch));
        thread.start();
        Thread thread1 = new Thread(new ReadFileService(latch));
        thread1.start();
    }
}
public class CreateFileService implements Runnable {
    private final CountDownLatch latch;
    public CreateFileService(CountDownLatch latch) {
        this.latch = latch;
    }
    @Override
    public void run() {
        ...
        latch.countDown();
    }
}
public class ReadFileService implements Runnable {
    private final CountDownLatch latch;
    public ReadFileService(CountDownLatch latch) {
        this.latch = latch;
    }
    @Override
    public void run() {
        latch.await();
        ...
    }
}

Ну, или можно изобрести собственный ̶в̶е̶л̶о̶с̶и̶п̶е̶д̶ CountDownLatch на низкоуровневых конструкциях wait/notify, но если делать это правильно, то кода синхронизации получится больше, чем кода логики.

Answer 2

Стартуйте второй поток с wait(). После того, как первый поток закончит работу посылайте notify(). Тем самым вы можете обеспечить очередность потоков.

READ ALSO
Как различать в строке пробел JAVA

Как различать в строке пробел JAVA

ЗдраствуйтеХочу при вводе данных вида: "privet kak dela" машина разделяла Строку на слова: "1 = привет; 2 = как; 3 = dela"

151
hibernate fetchmode для FetchType.LAZY

hibernate fetchmode для FetchType.LAZY

Не могу понять поведение Hibernate если для связанной коллекции будет FetchTypeLAZY

183
Проблема с cookies в JSF (Java Server Faces)

Проблема с cookies в JSF (Java Server Faces)

Есть JSF приложение, в котором по нажатию на кнопку логин:

164
Не получается изменить цвет NavBar (Android)

Не получается изменить цвет NavBar (Android)

Никак не получается изменить цвет NavBar'a в андроид приложенииПробовал прописывать в resources/style:

202