A co robi jeszcze ten watek ktory startujesz z maina? Bo jesli tylko wklada nowe watki do listy to mozesz to zrobic w watku main i nie masz problemu.
Jesli musi byc tak jak pokazujesz - aby miec pewnosc, ja bym czekal w watku main na 'zdarzenie' ze wszystkie watki sie znajduja w liscie (wzglednie, jesli sprawdzasz tylko czy chociaz jeden watek tam jest, zdarzeie moze byc generowane po pierwszym wlozeniu watku). Ten drugi watek w opodiwenim momencie (wlozyl 1 lub wiecej watkow do listy) generuje zdarzenie, ktore aktywuje main i ten sobie costam sprawdza.
To 'zdarzenie' mozesz zaimplementowac na bardzo wiele sposobow. Mozesz zrobic zwykle wait/notify, mozesz zrobic za pomoca klas z java.util.concurrent.
Zwykle monitory:
Kopiuj
package test;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
private static List<String> list = new ArrayList<String>();
private static boolean ready = false;
public static void main(String[] args) {
ExecutorService exec = Executors.newFixedThreadPool(1);
exec.execute(new Runnable() {
@Override
public void run() {
if (new Random().nextBoolean()) {
System.out.println("adding element");
list.add("some element");
} else {
System.out.println("not adding any element");
}
ready = true;
synchronized (Main.class) {
Main.class.notify();
}
}
});
synchronized (Main.class) {
while (!ready) {
try {
Main.class.wait();
} catch (InterruptedException e) {
}
}
}
if (list.isEmpty()) {
System.out.println("empty");
} else {
System.out.println("not empty");
}
}
}
Monitory z java.util.concurrent:
Kopiuj
package test;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Main {
private static List<String> list = new ArrayList<String>();
private static boolean ready;
private static Condition readyCondition;
public static void main(String[] args) {
final Lock lock = new ReentrantLock();
readyCondition = lock.newCondition();
ExecutorService exec = Executors.newFixedThreadPool(1);
exec.execute(new Runnable() {
@Override
public void run() {
if (new Random().nextBoolean()) {
System.out.println("adding element");
list.add("some element");
} else {
System.out.println("not adding any element");
}
ready = true;
lock.lock();
try {
readyCondition.signal();
} finally {
lock.unlock();
}
}
});
lock.lock();
try {
while (!ready) {
readyCondition.await();
}
} catch (InterruptedException e) {
} finally {
lock.unlock();
}
if (list.isEmpty()) {
System.out.println("empty");
} else {
System.out.println("not empty");
}
}
}
Struktury java.util.concurrent wyzszego poziomu:
Kopiuj
package test;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
private static List<String> list = new ArrayList<String>();
private static CyclicBarrier barrier = new CyclicBarrier(2);
public static void main(String[] args) throws BrokenBarrierException, InterruptedException {
ExecutorService exec = Executors.newFixedThreadPool(1);
exec.execute(new Runnable() {
@Override
public void run() {
if (new Random().nextBoolean()) {
System.out.println("adding element");
list.add("some element");
} else {
System.out.println("not adding any element");
}
try {
barrier.await();
} catch (InterruptedException e) {
} catch (BrokenBarrierException e) {
}
}
});
barrier.await();
if (list.isEmpty()) {
System.out.println("empty");
} else {
System.out.println("not empty");
}
}
}
To tylko pare przykladow, ktore mozna mnozyc. Nie zakladaj ze obsluga wyjatkow w tym kodzie jest 100% poprawna, tak samo jak to ze niezamykanie executora jest poprawne - zrobilem pare skrotow.