Próba zrozumienia synchronized

0

Myślałem że rozumiem zasadę działania synchronized w jave ale chyba jednak tak nie jest stworzyłem sobie prościutki programik:

public class Main {
    public static void main(String[] args) {
        Thread a= new A();
        Thread b= new Thread(new B());
        a.start();
        b.start();
    }
    public synchronized static void wypisz(String tekst){
            System.out.println(tekst);
    }
}

public class A extends Thread{
    public void run() {
        while(true){
            Main.wypisz("A");
        }
    }
} 

public class B implements Runnable {
    public void run() {
        while (true) {
            Main.wypisz("B");
        }
    }
}

Zakładałem że skoro startuje wątek "a" to zanim on wykona to proste wypisanie "b" będzie już czekał na monitorze to znaczy wątki będą na przemian wypisywać na konsole ciąg ababababab tymczasem dostaje długie ciągi literek "A" z rzadka przerywanych ciągami literek "B", zastanawiam się co mi tu umyka;/
wydłużałem czas operacji wypisz, usypiałem wątki na pewien czas to pozwala zbliżyć się do wspominanej przeplatanki, ale to nie jest to... Otrzymanie takiego efektu semaforami to pikuś ale czemu nie udaje mi się tego zrobić synchronized nie mam pojęcia :(
Był bym wdzięczny za jakąś wskazówkę

0

Synchronized zapewnia, ze tej metody danego obiektu (!) nie wywolaja NA RAZ dwa watki. Gdyby byla sytuacja, ze oba watki wypisuja teksty: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" i "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" to masz pewnosc, ze ciagi, ktore otrzymasz to NIE beda np: "AAABBBBAAAABABABBABBAAAAABABBABBBAAABA" (zakladajac, ze metoda wypisz wypisywalaby znak po znaku), tylko beda to: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBB" i tak dalej.

0

@up:
Nietrafione wytłumaczenie. Kolega wypisuje znak po znaku, a nie ciągami.

Dobre wytłumaczenie:
Java używa normalnych wątków (kiedyś używała swoich ale to już zamierzchłe czasy), a te natywne wątki działają przez kilkanaście milisekund zanim się przełączą na inne. Przez te kilkanaście milisekund spokojnie zdąży się wypisać dość dużo literek, dlatego mamy długię ciągi A i długie ciągi B (ja takie coś u siebie zaobserwowałem).

Dodaj Thread.sleep(10) do pętli w obydwu wątkach i zobaczysz przeplatankę.

0

Synchronize wg mojej wiedzy działa tak: wątek który wywołuje metodę synchronizowaną zajmuje monitor uniemożliwiając tym samym innym watką wejście do tegoż monitora za zatem wykonanie jakichkolwiek jego metod, wątek który będzie próbował to zrobić zostanie zatrzymany na monitorze, i wznowiony gdy tylko poprzedni wątek opuści monitor - Tymczasem:
wg tego co napisałem przewidywałem przeplatankę ababab ale nawet jak usypiam na troszkę wątki otrzymuje aaaabbbbbbaaaaa, tak jak by wątek nie opuszczał monitora zaraz po zakończeniu się metody wypisz o.0
Nie mogę jakoś przełknąć dlaczego wątek zajmuje monitor na czas dłuższy niż wykonanie pojedynczej metody wypisz.

0

Watek zwalnia monitor, ale wcale nie jest nigdzie powiedziane ze zaraz go znowu nie dostanie - przeciez jak tylko zwolni monitor, to w systemie znowu sa 2 watki ktore moga go dostac, a runtime nie jest tzw 'fair' - to ze ktos czeka juz na monitor, nie znaczy ze dostanie go jako pierwszy. Aby to zaimplementowac musisz uzyc np wait i notify/All albo monitorow ktore implementuje fainess - synchronized na to nie pozwala, ale sa klasy wyzszego poziomu ktore pozwalaja - java.util.concurrent.lock.ReentrantLock, ale i tak nie masz zapewnionego wyniku jaki chcesz (choc pewnie taki otrzymasz).
Aby miec pewnosc uzyj albo synchronized / wait / notify lub ReentrantLock z Conditiona / await / signal. Poszukaj na forum, jakis czas temu (rok, moze 2) sam pisalem przykladowy kod ktory robil to co chcesz, a i wiem ze jest wiecej przykladow.

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