Java - wielowątkowość

0

Cześć, mam program, w którym pobieram listę plików z folderu i w pętli dla każdego pliku wywołuję pewną aplikację z parametrem - właśnie tym plikiem, aplikacja zwraca mi wynik i zapisuję to do bazy. Jednak takie jedno wywołanie trwa kilka sekund i przy wielu plikach będzie to trwało bardzo bardzo długo. Czy da radę to podzielić na kilka wątków, żeby trwało to szybciej? Jak podzielić tablicę Stringów ze ścieżkami na każdy wątek w taki sposób, żeby inny wątek nie korzystał już z tego elementu tablicy?

0

Pokaż kod klasy, którego używasz do pobierania tych plikówi jak wygląda ta tablica Stringów.
Ja bym to zrobił tak: użył DirectoryStream (chyba, że podkatalogi również, wtedy walkFileTree) i z gotową ArrayList<Path/File> wywoływał wątki asynchronicznie albo w póli wątków przez ExecutorService

0

Listę plików pobrałem tak do ArrayList - z tablicy na ArrayListę przeszedłem bo myślałem o usuwaniu

package pl.starits;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class Main {
	public static ArrayList<File> listOfFiles;
	
	public static void main(String[] args) {
		Map<String, String> imagesPlates = new HashMap<String, String>();
		Main obj = new Main();

		String alprDirectory = "openalpr_64";
		String imagesDirectory = "images";

		String alprCommand = alprDirectory + "/alpr";

		File folder = new File(imagesDirectory);
		File[] listOfFilesArray = folder.listFiles();
		listOfFiles = new ArrayList<File>(Arrays.asList(listOfFilesArray));

		for (int i = 0; i < 10; i++) {
			if (listOfFiles.get(i).isFile()) {
				String image = listOfFiles.get(i).getAbsolutePath();
				String command = alprCommand + " " + image;
				String plateNumber = obj.executeCommand(command);
				if (!plateNumber.isEmpty()) {
					imagesPlates.put(plateNumber, image);
				}
			}
		}
		for (Map.Entry<String, String> entry : imagesPlates.entrySet()) {
			System.out.println(entry.getKey() + "         " + entry.getValue());
		}
	}

	private String executeCommand(String command) {
		boolean flag = true;
		StringBuffer output = new StringBuffer();

		Process p;
		try {
			p = Runtime.getRuntime().exec(command);
			p.waitFor();
			BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));

			String line = "";
			while ((line = reader.readLine()) != null && flag) {
				if (line.contains("confidence")) {
					line = line.trim();
					line = line.replaceAll("\\s+", "");
					line = line.substring(1, line.indexOf("confidence"));
					output.append(line);
					flag = false;
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return output.toString();
	}
}

1

Polecałbym użyć puli watków ForkJoin framework albo tak jak kolega wspomniał wcześniej - ExecutorService/ExecutorThreadPool. Czyli musisz zrobić klasę, która będzie odpowiadać zadaniu, które chcesz wykonać i pozbierać wyniki

http://tutorials.jenkov.com/java-util-concurrent/java-fork-and-join-forkjoinpool.html
https://www.javacodegeeks.com/2013/01/java-thread-pool-example-using-executors-and-threadpoolexecutor.html

2

Bardzo na skróty:

public class CF {

	public static void main(String[] args) throws IOException {
		Files.list(Paths.get("."))
			.map(f-> CompletableFuture.supplyAsync(()->magia(f)).thenAcceptAsync(i->zapiszDoBazy(i)))
				.forEach(f ->f.thenAcceptAsync(x-> System.out.println(".")));
	}

	private static void zapiszDoBazy(Integer i) {
		//....
	}

	private static Integer magia(Path f) {
		return 0;
	}
}

Masz listę plików i dla każdego tworzysz CompletableFuture, który będzie robił magię i zapisywał wynik do bazy. Na koniec wykropkowujesz sobie zakończone zadania.

1 użytkowników online, w tym zalogowanych: 0, gości: 1