Массив общего буфера не обновляется должным образом в разных потоках

#java #multithreading

Вопрос:

Я пытаюсь написать программу, которая берет фрагменты входного текстового файла и перемещает их в соответствии с введенным пользователем шаблоном. Потоки не должны быть синхронизированы или параллельны, так как каждому из них присваиваются свои собственные индексы из текстового файла для работы. Затем он предназначен для вставки символов в назначенный ему фрагмент в соответствующее место в массиве символов буфера.

Однако всякий раз, когда я запускаю свой код, только первый фрагмент (вместо всех фрагментов, переставленных в соответствующем шаблоне) оказывается в массиве символов. Я дважды проверил значения, переданные классу Swapper, и подтвердил, что смещения и интервалы верны. Вот мой (свернутый) код:

TextSwap.java

 public class TextSwap {
    private static String readFile(String filename, int chunkSize) throws Exception {
        String line;
        StringBuilder buffer = new StringBuilder();
        File file = new File(filename);
        BufferedReader br = new BufferedReader(new FileReader(file));
        while ((line = br.readLine()) != null){
            buffer.append(line);
        }
        br.close();
        return buffer.toString();
    }

    private static char[] runSwapper(String content, int chunkSize, int numChunks) {
        Interval[] intervals = new Interval[5];
        
        intervals[0] = new Interval(0,4);
        intervals[1] = new Interval(4,8);
        intervals[2] = new Interval(8,12);
        intervals[3] = new Interval(12,16);
        intervals[4] = new Interval(16,20);
        
        char[] buffer = new char[content.length()];
        Thread[] threads = new Thread[numChunks];
        for(int i = 0; i < numChunks; i  ) {
            Interval current = intervals[i];
            threads[i] = new Thread(new Swapper(current, content, buffer, i * chunkSize));
            threads[i].start();
        }
        
        for(int i = 0; i < numChunks; i  ) {
            try {
                threads[i].join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return buffer;
    }

    private static void writeToFile(String contents, int chunkSize, int numChunks) throws Exception {
        char[] buff = runSwapper(contents, chunkSize, contents.length() / chunkSize);
        System.out.println(buff);
        PrintWriter writer = new PrintWriter("src/proj/output.txt", "UTF-8");
        writer.print(buff);
        writer.close();
    }

    public static int getNumber(char val) {
        return Character.getNumericValue(val) - 9;
    }

    public static void main(String[] args) {
        if (args.length != 2) {
            System.out.println("Usage: java TextSwap <chunk size> <filename>");
            return;
        }
        String contents = "";
        int chunkSize = Integer.parseInt(args[0]);
        try {
            contents = readFile(args[1],chunkSize);
            writeToFile(contents, chunkSize, contents.length() / chunkSize);
        } catch (Exception e) {
            System.out.println("Error with IO: "   e.getMessage());
            return;
        }
    }
}
 

Interval.java

 public class Interval {
    private int x;
    private int y;
    
    public Interval(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int getX() {
        return this.x;
    }

    public int getY() {
         return this.y;
    }

    public String toString() {
        return "("   this.x   ", "   this.y   ")";
    }
}
 

Swapper.java

 public class Swapper implements Runnable {
    private int offset;
    private Interval interval;
    private String content;
    private char[] buffer;

    public Swapper(Interval interval, String content, char[] buffer, int offset) {
        this.offset = offset;
        this.interval = interval;
        this.content = content;
        this.buffer = buffer;
    }

    @Override
    public void run() {
        // TODO: Implement me!
        int x = interval.getX();
        int y = interval.getY();
        for(int i = x; i < (y - x); i  ) {
            buffer[offset   (i - x)] = content.charAt(i);
        }
    }
}
 

Содержимое текстового файла:
AAAABBBBCCCCDDDDEEEE

Жестко закодированный шаблон:

bcade

Команда аргументы:

java TextSwap 4 letters.txt (Где 4-это chunkSize )

Желаемый результат: BBBBCCCCAAAADDDDEEEE

Фактический объем производства: AAAA

Комментарии:

1. Установите точку останова for (int i = x; i < (y - x); i ) { и посмотрите на значение i < y-x для каждого из ваших потоков. (Или просто рассчитайте это на бумаге, вам нужно только посмотреть на первую итерацию)

2. @tgdavies Ах, значит, я идиот. Спасибо.

3. Я думаю, что ошибка заключалась в смешивании смещений и абсолютных индексов таким образом, что это привело к путанице. И не писать модульные тесты. Модульный тест для Swapper очень быстро выявил бы проблему.