簡體   English   中英

Java多線程與打開文件

[英]Java Multithreading with Opening Files

我有一個txt文件: order_me.txt ,其中有一些整數需要使用4個線程進行排序。 他們需要同時工作,但不能做同樣的事情。 我已經設法對整數進行排序,但是某些方法無法正常工作...

這是線程類:

public class Threading {

    static List<Integer> integersCopy = new ArrayList<>();

    public static void main(String[] args) {
        openFile();
        Thread t1 = new Thread(new Command("thread 1", integersCopy));
        t1.start();

        Thread t2 = new Thread(new Command("thread 2", integersCopy));
        t2.start();

        Thread t3 = new Thread(new Command("thread 3", integersCopy));
        t3.start();

        Thread t4 = new Thread(new Command("thread 4", integersCopy));
        t4.start();

        try {
            if (t1.isAlive())
                t1.join();
            if (t2.isAlive())
                t2.join();
            if (t3.isAlive())
                t3.join();
            if (t4.isAlive())
                t4.join();
        } catch (Exception e) {
            System.out.println("Exception with threads");
        }
    }

    public static void openFile() {
        File file = new File("order_me.txt");
        try {
            Scanner scanner = new Scanner(file);
            List<Integer> integers = new ArrayList<>();
            while (scanner.hasNext()) {
                if (scanner.hasNextInt()) {
                    integers.add(scanner.nextInt());
                } else {
                    scanner.next();
                }
            }
            integersCopy = integers;
            System.out.println("File opened successfully");

        } catch (Exception e) {
            System.out.println("Triggered exception");
        }
    }

這是排序類:

    import java.util.Collections;
    import java.util.List;

    public class Command implements Runnable {
    String threadName;
    List<Integer> listOfInts;

    Command(String name, List<Integer> list) {
        threadName = name;
        listOfInts = list;
    }

    @Override
    public void run() {
        for (int i = 0; i < listOfInts.size(); i++) {
            Collections.sort(listOfInts);
            System.out.print(+listOfInts.get(i) + " ");
        }
    }
}

一旦一個線程對整數進行了排序,就沒有必要在多個線程中嘗試執行相同的操作,事實上,由於這樣做不是以線程安全的方式進行的,因此很可能破壞列表。

簡而言之,使用一個線程。

您正在變異幾個線程上的共享List ArrayList不是線程安全的 :您需要使用線程安全的Collection或使用Collections.synchronizedList

而且,如果您在每個線程中對相同的列表進行排序,那么您的實現可能是錯誤的:

  • 您應該在父線程中閱讀一次列表
  • 您應該按線程數對列表進行拆分,並對每個線程中的每個子列表進行排序。 在這種情況下,這就是Thread的目的:划分工作。
  • 然后,您應該在父線程中加入子列表:在加入過程中,您將必須進行排序。 由於對每個子列表進行了排序,因此您可以使用更快的排序(例如:如果子列表A的第一項在子列表B的末尾之后,則可以將A的所有項添加到B中)或標准排序。

另外,您可以使用Stream來做到這一點:

  • parallel()方法使Stream使用多個線程。
  • ForkJoinPool用於使用另一個線程池(請參見此SO答案 )。 舉個例子來說可能沒有用。
  • 不幸的是, Scanner不能轉換為IntStreamStream 您需要使用Files.linesPattern來按空格( \\s+ )分隔行。
  • 我們使用flatMapToIntOptionalInt轉換為IntStream (對於無效數字,該IntStream將為空,例如*a4 )。
  • sorted()確保我們使用默認排序進行排序。 使用比較器進行排序將需要正常的Stream,因此,將flatMapToInt更改為flatMap
  • 在那種情況下, toArray()可能比在第二個示例中使用Integer ArrayList更好。

使用Java 11測試的代碼:

  public static void main(final String[] args) throws Exception {
    final Pattern splitter = Pattern.compile("\\s+");
    // see
    // 
    final ForkJoinPool forkJoinPool = new ForkJoinPool();
    final Future<int[]> future = forkJoinPool.submit(() -> {
      try (final Stream<String> lines = Files.lines(Paths.get("myfile.txt"), StandardCharsets.UTF_8)) {
        return lines.parallel() // use default parallel ExecutorService
            .flatMap(splitter::splitAsStream) // tokenize input
            .flatMapToInt(s -> parseInt(s).stream()) // convert to number (eg: nextInt())
            .sorted().toArray();
      }
    });

    final int[] result = future.get();
    System.out.println("result.length: " + result.length);
    // Arrays.stream(result).forEach(System.out::println);
    final Future<List<Integer>> future2 = forkJoinPool.submit(() -> {
      try (Stream<String> lines = Files.lines(Paths.get("myfile.txt"), StandardCharsets.UTF_8)) {
        return lines.parallel() // use default parallel ExecutorService
            .flatMap(splitter::splitAsStream) // tokenize input
            .flatMapToInt(s -> parseInt(s).stream()) // convert to number (eg: nextInt())
            .sorted().collect(ArrayList::new, List::add, List::addAll) // probably best to use
                                                                       // array.
        ;
      }
    });
    final List<Integer> result2 = future2.get();
    System.out.println("result2.length: " + result2.size());
  }

  static OptionalInt parseInt(final String s) {
    try {
      return OptionalInt.of(Integer.parseInt(s));
    } catch (final NumberFormatException e) {
      return OptionalInt.empty();
    }
  }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM