wątek main a pozostałe wątki

0

Cześć :)
Załóżmy, że mamy dwa wątki- wątek główny i w tym wątku odpalamy w sposób następujący:

ExecutorService exec = Executors.newFixedThreadPool(1);
exec.execute(obiektWatku);

Noi w tym wątku wkładamy pewne rzeczy do wspólnej listy dla tych wątków. Sytuacja wygląda tak, że main() ulega zakończeniu zanim zdąży ten drugi wątek powkładać do listy i przez to main widzi listę pustą. Jak zrobić, żeby widział?
Nie mówię, że musi tak być, żeby w mainie czekać na ten drugi wątek. Nie wiem jak powinno to wyglądać. Normalnie powinno być tak, że ostatnim wątkiem jest main czy też nie? Jeżeli nie to jakoś przeprojektuje program, ale też warto dowiedzieć się jak poczekać na zakończenie innego wątku :)

0

Zrób w mainie pętle, która sprawdza czy wszystkie pozostałe wątki są 'alive', jeżeli już żadnego nie będzie to koniec pętli i koniec głównego wątku.

0

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:

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) { // there might be spurious wakeups and interrupts, needs a loop
                try {
                    Main.class.wait();
                } catch (InterruptedException e) {
                    // ignore, but think about it
                }
            }
        }

        if (list.isEmpty()) {
            System.out.println("empty");
        } else {
            System.out.println("not empty");
        }
    }
}

Monitory z java.util.concurrent:

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) {  // there might be spurious wakeups and interrupts, needs a loop
                readyCondition.await();
            }
        } catch (InterruptedException e) {
            // ignore
        } finally {
            lock.unlock();
        }

        if (list.isEmpty()) {
            System.out.println("empty");
        } else {
            System.out.println("not empty");
        }
    }
}

Struktury java.util.concurrent wyzszego poziomu:

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) {
                    // ignore
                } catch (BrokenBarrierException e) {
                    // ignore
                }
            }
        });

        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.

0

Petla w drugim przykladzie powinna wygladac raczej tak:

        try {
            while (!ready) {  // there might be spurious wakeups and interrupts, needs a loop
                try {
                    readyCondition.await();
                } catch (InterruptedException exc) {
                    // ignore
                }
            }
        } finally {
            lock.unlock();
        }
0

Ah jej, naprawde powazny blad. Bys lepiej poprawil jak umiesz.

0

W tym celu najlepiej zastosować klasę CountDownLatch - http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html

0

Jak napisalem mozliwosci jest bardzo duzo, mozna i CDLatch. Mi sie jednak wydaje to dosc skomplikowane, osobiscie bym pierdalnal na notify/wait ;d Ale pan Seliga by znalazl 30 bugow a 30 by nie znalazl...

0

Zamiast wait/notify można użyć Future<T> z java.util.concurrent

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