Дождитесь завершения дочерних потоков: Java
Описание проблемы: -
Шаг 1: Возьмите FILE_NAME пользователя из основного потока.
Шаг 2: выполните 10 операций над этим файлом (например, графы подсчета, строки подсчета и т.д.), и все эти 10 операций должны быть в септических потоках. Это означает, что должно быть 10 дочерних потоков.
Шаг 3: Основной поток ожидает завершения всех этих дочерних потоков.
Шаг 4: результат печати.
Что я сделал: -
Я сделал пример кода с 3 потоками. Мне не нужен код операции с вашей стороны.
public class ThreadTest {
// This is object to synchronize on.
private static final Object waitObject = ThreadTest.class;
// Your boolean.
private static boolean boolValue = false;
public final Result result = new Result();
public static void main(String[] args) {
final ThreadTest mytest = new ThreadTest();
System.out.println("main started");
new Thread(new Runnable() {
public void run() {
System.out.println("Inside thread");
//Int initialiser
new Thread(new Runnable() {
public void run() {
System.out.println("Setting integer value");
mytest.result.setIntValue(346635);
System.out.println("Integer value seted");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
//String initialiser
new Thread(new Runnable() {
public void run() {
System.out.println("Setting string value");
mytest.result.setStringValue("Hello hi");
System.out.println("String value seted");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
//Boolean initialiser
new Thread(new Runnable() {
public void run() {
System.out.println("Setting boolean value");
mytest.result.setBoolValue(true);
System.out.println("Boolean value seted");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
System.out.println("Thread is finished");
//Notify to main thread
synchronized (ThreadTest.waitObject) {
ThreadTest.boolValue = true;
ThreadTest.waitObject.notifyAll();
}
}
}).start();
try {
synchronized (ThreadTest.waitObject) {
while (!ThreadTest.boolValue) {
ThreadTest.waitObject.wait();
}
}
} catch (InterruptedException ie) {
ie.printStackTrace();
}
System.out.println("main finished");
System.out.println("Result is : " + mytest.result.toString());
}
}
Проблема: -
Мой выше код не дает правильного ответа. Как я могу это сделать?
Альтернативные решения:
Класс CountDownLatch делает то же самое. Но я не хочу использовать этот класс.
Я посмотрел подобное подобное решение, и я хочу использовать только методы Thread.
Ответы
Ответ 1
Вы можете сделать:
Thread t = new Thread() {
public void run() {
System.out.println("text");
// other complex code
}
};
t.start();
t.join();
Таким образом, вы будете ждать окончания потока и просто продолжить. Вы можете join
несколько потоков:
for (Thread thread : threads) {
thread.join();
}
Ответ 2
Я бы рекомендовал сначала взглянуть на структуру Executors, а затем посмотреть CompletionService.
Тогда вы можете написать что-то вроде этого:
ExecutorService executor = Executors.newFixedThreadPool(maxThreadsToUse);
CompletionService completion = new ExecutorCompletionService(executor);
for (each sub task) {
completion.submit(new SomeTaskYouCreate())
}
// wait for all tasks to complete.
for (int i = 0; i < numberOfSubTasks; ++i) {
completion.take(); // will block until the next sub task has completed.
}
executor.shutdown();
Ответ 3
В Java 8 гораздо лучший подход - использовать parallelStream()
Примечание: гораздо проще увидеть, что делают эти фоновые задачи.
public static void main(String[] args) {
Stream.<Runnable>of(
() -> mytest.result.setIntValue(346635),
() -> mytest.result.setStringValue("Hello hi"),
() -> mytest.result.setBoolValue(true) )
.parallel()
.forEach(Runnable::run);
System.out.println("main finished");
System.out.println("Result is : " + mytest.result.toString());
}
Я вынул информацию об отладке и сон, поскольку они не изменяют результат.
Ответ 4
Есть много способов приблизиться к этому. Рассмотрим CountDownLatch:
import java.util.concurrent.CountDownLatch;
public class WorkerTest {
final int NUM_JOBS = 3;
final CountDownLatch countDownLatch = new CountDownLatch(NUM_JOBS);
final Object mutex = new Object();
int workData = 0;
public static void main(String[] args) throws Exception {
WorkerTest workerTest = new WorkerTest();
workerTest.go();
workerTest.awaitAndReportData();
}
private void go() {
for (int i = 0; i < NUM_JOBS; i++) {
final int fI = i;
Thread t = new Thread() {
public void run() {
synchronized(mutex) {
workData++;
}
try {
Thread.sleep(fI * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
countDownLatch.countDown();
}
};
t.start();
}
}
private void awaitAndReportData() throws InterruptedException {
countDownLatch.await();
synchronized(mutex) {
System.out.println("All workers done. workData=" + workData);
}
}
}
Ответ 5
Вы можете выбрать CountDownLatch из java.util.concurrent
. Из JavaDocs:
Средство синхронизации, которое позволяет одному или нескольким потокам ждать, пока набор операций, выполняемых в других потоках завершается.
Пример кода:
import java.util.concurrent.CountDownLatch;
public class Test {
private final ChildThread[] children;
private final CountDownLatch latch;
public Test() {
this.children = new ChildThread[4];
this.latch = new CountDownLatch(children.length);
children[0] = new ChildThread(latch, "Task 1");
children[1] = new ChildThread(latch, "Task 2");
children[2] = new ChildThread(latch, "Task 3");
children[3] = new ChildThread(latch, "Task 4");
}
public void run() {
startChildThreads();
waitForChildThreadsToComplete();
}
private void startChildThreads() {
Thread[] threads = new Thread[children.length];
for (int i = 0; i < threads.length; i++) {
ChildThread child = children[i];
threads[i] = new Thread(child);
threads[i].start();
}
}
private void waitForChildThreadsToComplete() {
try {
latch.await();
System.out.println("All child threads have completed.");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private class ChildThread implements Runnable {
private final String name;
private final CountDownLatch latch;
protected ChildThread(CountDownLatch latch, String name) {
this.latch = latch;
this.name = name;
}
@Override
public void run() {
try {
// Implementation
System.out.println(name + " has completed.");
} finally {
latch.countDown();
}
}
}
public static void main(String[] args) {
Test test = new Test();
test.run();
}
}
Выход:
Задание 1 завершено.
Задание 4 завершено.
Задание 3 завершено.
Задание 2 завершено.
Все дочерние потоки завершены.