Dwa wątki

0

Mam pewien problem, w wątku pierwszym uruchomiana jest metoda inkrementuj() i zmienna i powinna mieć wartość 0, a zmienna stanKonta powinna mieć wartość 1, a u mnie maszyna wirtualna pokazuje komunikat "Wykonuje to Wątek 1 Stan konta wynosi: 2 a i wynosi 0". Nie rozumiem skąd zmienna stanKonta ma wartość 2 a zmienna i wartość 0. Proszę o pomoc.

Tutaj przedstawiam kod:

class TestSynchro implements Runnable{
    private int stanKonta;

    public void run(){
        for (int i=0;i<50;i++){
            inkrementuj();
            System.out.println("Wykonuje to " + Thread.currentThread().getName() + " Stan konta wynosi: " + stanKonta + " a i wynosi " + i);
        }
    }
    public synchronized void inkrementuj(){
        int i = stanKonta;
        stanKonta = i + 1;
    }
}
public class TestSynchronizacji {
    public static void main(String[] args){
        TestSynchro zadanie = new TestSynchro();
        Thread watek1 = new Thread(zadanie);
        Thread watek2 = new Thread(zadanie);
        watek1.setName("Wątek 1");
        watek2.setName("Wątek 2");
        watek1.start();
        watek2.start();
    }
} 
0

Przecież nie synchronizujesz wypisywania, więc w chwili kiedy wypisujesz to zmienne mogą być aktualnie zmieniane. Nie widze tutaj nic dziwnego. Zanim zdążyłeś wypisac oba wątki wykonały "inkremenetuj".

0

Dopiero zaczynam się uczyć i dalej nie rozumiem dlaczego jak wypisuje to nie ma dwóch wątków w jednej pętli tylko np. jak niżej, że w pętli 0 tylko wątek A się wykonał a potem po pętli drugiej dopiero kontynuowana jest pętla 0? Proszę o pomoc

W pętli: 0 Wykonuje to Wątek A stan konta: 2
W pętli: 1 Wykonuje to Wątek A stan konta: 3
W pętli: 2 Wykonuje to Wątek A stan konta: 4
W pętli: 0 Wykonuje to Wątek B stan konta: 2
W pętli: 3 Wykonuje to Wątek A stan konta: 5
W pętli: 4 Wykonuje to Wątek A stan konta: 7
W pętli: 5 Wykonuje to Wątek A stan konta: 8
W pętli: 6 Wykonuje to Wątek A stan konta: 9
W pętli: 1 Wykonuje to Wątek B stan konta: 6

0

Edit: @rudinho. Przepraszam za wprowadzenie w błąd. Rzeczywiście twoje wątki współdzielą obiekt, ale wywołanie jest takie a nie inne z powodu metody. Daj wypisywanie w metodzie zsynchronizowanej:

    public synchronized void inkrementuj(){
        int i = stanKonta;
        stanKonta = i + 1;
        System.out.println("Wykonuje to " + Thread.currentThread().getName() + " Stan konta wynosi: " + stanKonta + " a i wynosi " + i);
    }
0

no ale teraz bezsens chyba bo wątki powinny się wykonywać raz ten raz ten, nie mamy wpływu na to a jak dodałem to co napisałeś to najpierw wykonuje się wątek A a dopiero potem B :/
Wykonuje to Wątek A i wynosi: 0 a stan konta wynosi 1
Wykonuje to Wątek A i wynosi: 1 a stan konta wynosi 2
Wykonuje to Wątek A i wynosi: 2 a stan konta wynosi 3
Wykonuje to Wątek A i wynosi: 3 a stan konta wynosi 4
Wykonuje to Wątek A i wynosi: 4 a stan konta wynosi 5
Wykonuje to Wątek A i wynosi: 5 a stan konta wynosi 6
Wykonuje to Wątek A i wynosi: 6 a stan konta wynosi 7
Wykonuje to Wątek A i wynosi: 7 a stan konta wynosi 8
Wykonuje to Wątek A i wynosi: 8 a stan konta wynosi 9
Wykonuje to Wątek A i wynosi: 9 a stan konta wynosi 10
Wykonuje to Wątek A i wynosi: 10 a stan konta wynosi 11
Wykonuje to Wątek A i wynosi: 11 a stan konta wynosi 12
Wykonuje to Wątek A i wynosi: 12 a stan konta wynosi 13
Wykonuje to Wątek A i wynosi: 13 a stan konta wynosi 14
Wykonuje to Wątek A i wynosi: 14 a stan konta wynosi 15
Wykonuje to Wątek A i wynosi: 15 a stan konta wynosi 16
Wykonuje to Wątek A i wynosi: 16 a stan konta wynosi 17
Wykonuje to Wątek A i wynosi: 17 a stan konta wynosi 18
Wykonuje to Wątek A i wynosi: 18 a stan konta wynosi 19
Wykonuje to Wątek A i wynosi: 19 a stan konta wynosi 20
Wykonuje to Wątek A i wynosi: 20 a stan konta wynosi 21
Wykonuje to Wątek A i wynosi: 21 a stan konta wynosi 22
Wykonuje to Wątek A i wynosi: 22 a stan konta wynosi 23
Wykonuje to Wątek A i wynosi: 23 a stan konta wynosi 24
Wykonuje to Wątek A i wynosi: 24 a stan konta wynosi 25
Wykonuje to Wątek A i wynosi: 25 a stan konta wynosi 26
Wykonuje to Wątek A i wynosi: 26 a stan konta wynosi 27
Wykonuje to Wątek A i wynosi: 27 a stan konta wynosi 28
Wykonuje to Wątek A i wynosi: 28 a stan konta wynosi 29
Wykonuje to Wątek A i wynosi: 29 a stan konta wynosi 30
Wykonuje to Wątek A i wynosi: 30 a stan konta wynosi 31
Wykonuje to Wątek A i wynosi: 31 a stan konta wynosi 32
Wykonuje to Wątek A i wynosi: 32 a stan konta wynosi 33
Wykonuje to Wątek A i wynosi: 33 a stan konta wynosi 34
Wykonuje to Wątek A i wynosi: 34 a stan konta wynosi 35
Wykonuje to Wątek A i wynosi: 35 a stan konta wynosi 36
Wykonuje to Wątek A i wynosi: 36 a stan konta wynosi 37
Wykonuje to Wątek A i wynosi: 37 a stan konta wynosi 38
Wykonuje to Wątek A i wynosi: 38 a stan konta wynosi 39
Wykonuje to Wątek A i wynosi: 39 a stan konta wynosi 40
Wykonuje to Wątek A i wynosi: 40 a stan konta wynosi 41
Wykonuje to Wątek A i wynosi: 41 a stan konta wynosi 42
Wykonuje to Wątek A i wynosi: 42 a stan konta wynosi 43
Wykonuje to Wątek A i wynosi: 43 a stan konta wynosi 44
Wykonuje to Wątek A i wynosi: 44 a stan konta wynosi 45
Wykonuje to Wątek A i wynosi: 45 a stan konta wynosi 46
Wykonuje to Wątek A i wynosi: 46 a stan konta wynosi 47
Wykonuje to Wątek A i wynosi: 47 a stan konta wynosi 48
Wykonuje to Wątek A i wynosi: 48 a stan konta wynosi 49
Wykonuje to Wątek A i wynosi: 49 a stan konta wynosi 50
Wykonuje to Wątek B i wynosi: 50 a stan konta wynosi 51
Wykonuje to Wątek B i wynosi: 51 a stan konta wynosi 52
Wykonuje to Wątek B i wynosi: 52 a stan konta wynosi 53
Wykonuje to Wątek B i wynosi: 53 a stan konta wynosi 54
Wykonuje to Wątek B i wynosi: 54 a stan konta wynosi 55
Wykonuje to Wątek B i wynosi: 55 a stan konta wynosi 56
Wykonuje to Wątek B i wynosi: 56 a stan konta wynosi 57
Wykonuje to Wątek B i wynosi: 57 a stan konta wynosi 58
Wykonuje to Wątek B i wynosi: 58 a stan konta wynosi 59
Wykonuje to Wątek B i wynosi: 59 a stan konta wynosi 60
Wykonuje to Wątek B i wynosi: 60 a stan konta wynosi 61
Wykonuje to Wątek B i wynosi: 61 a stan konta wynosi 62
Wykonuje to Wątek B i wynosi: 62 a stan konta wynosi 63
Wykonuje to Wątek B i wynosi: 63 a stan konta wynosi 64
Wykonuje to Wątek B i wynosi: 64 a stan konta wynosi 65
Wykonuje to Wątek B i wynosi: 65 a stan konta wynosi 66
Wykonuje to Wątek B i wynosi: 66 a stan konta wynosi 67
Wykonuje to Wątek B i wynosi: 67 a stan konta wynosi 68
Wykonuje to Wątek B i wynosi: 68 a stan konta wynosi 69
Wykonuje to Wątek B i wynosi: 69 a stan konta wynosi 70
Wykonuje to Wątek B i wynosi: 70 a stan konta wynosi 71
Wykonuje to Wątek B i wynosi: 71 a stan konta wynosi 72
Wykonuje to Wątek B i wynosi: 72 a stan konta wynosi 73
Wykonuje to Wątek B i wynosi: 73 a stan konta wynosi 74
Wykonuje to Wątek B i wynosi: 74 a stan konta wynosi 75
Wykonuje to Wątek B i wynosi: 75 a stan konta wynosi 76
Wykonuje to Wątek B i wynosi: 76 a stan konta wynosi 77
Wykonuje to Wątek B i wynosi: 77 a stan konta wynosi 78
Wykonuje to Wątek B i wynosi: 78 a stan konta wynosi 79
Wykonuje to Wątek B i wynosi: 79 a stan konta wynosi 80
Wykonuje to Wątek B i wynosi: 80 a stan konta wynosi 81
Wykonuje to Wątek B i wynosi: 81 a stan konta wynosi 82
Wykonuje to Wątek B i wynosi: 82 a stan konta wynosi 83
Wykonuje to Wątek B i wynosi: 83 a stan konta wynosi 84
Wykonuje to Wątek B i wynosi: 84 a stan konta wynosi 85
Wykonuje to Wątek B i wynosi: 85 a stan konta wynosi 86
Wykonuje to Wątek B i wynosi: 86 a stan konta wynosi 87
Wykonuje to Wątek B i wynosi: 87 a stan konta wynosi 88
Wykonuje to Wątek B i wynosi: 88 a stan konta wynosi 89
Wykonuje to Wątek B i wynosi: 89 a stan konta wynosi 90
Wykonuje to Wątek B i wynosi: 90 a stan konta wynosi 91
Wykonuje to Wątek B i wynosi: 91 a stan konta wynosi 92
Wykonuje to Wątek B i wynosi: 92 a stan konta wynosi 93
Wykonuje to Wątek B i wynosi: 93 a stan konta wynosi 94
Wykonuje to Wątek B i wynosi: 94 a stan konta wynosi 95
Wykonuje to Wątek B i wynosi: 95 a stan konta wynosi 96
Wykonuje to Wątek B i wynosi: 96 a stan konta wynosi 97
Wykonuje to Wątek B i wynosi: 97 a stan konta wynosi 98
Wykonuje to Wątek B i wynosi: 98 a stan konta wynosi 99
Wykonuje to Wątek B i wynosi: 99 a stan konta wynosi 100

0

@rudinho ech doczytaj podstawy...

  1. Zanim jeden wątek wystartuje to drugi już skończy. Puść to na tysiące iteracji jak chcesz coś zobaczyć.
  2. Nie bardzo rozumiem co wg ciebie znaczy

dlaczego jak wypisuje to nie ma dwóch wątków w jednej pętli tylko np. jak niżej, że w pętli 0 tylko wątek A się wykonał a potem po pętli drugiej dopiero kontynuowana jest pętla 0

Nie ma tu żadnej "kontynuacji"! Każdy wątek ma SWOJĄ pętlę i ją wykonuje kiedy może. Wątki nie działają jednocześnie / równolegle, a przynajmniej nie zawsze. Współbieżnosć to nie równoległość. Wątek dostaje procesor na jakiś czas i wykonuje sobie swoje operacje. Nawet jeśli masz > 1 rdzeń procesora to nie ma żadnej pewności że akurat jeden twój wątek dostanie jeden procesor a drugi drugi i to jeszcze w tym samym czasie żeby ci się to wypisało tak jakbyś chciał ;]

0
rudinho napisał(a):

no ale teraz bezsens chyba bo wątki powinny się wykonywać raz ten raz ten, nie mamy wpływu na to a jak dodałem to co napisałeś to najpierw wykonuje się wątek A

Tak jak Ci pisałem przed edycją. Współbieżność nie gwarantuje, że wątki będą wykonywać się jeden po drugim akurat po jednej iteracji w pętli. Może być tak, że najpierw WątekA wykona 4 pętle potem WątekB 2 itd.
Współbieżność daje wrażenie równoległości i jest osiągane przez mechanizm przydzielania czasu procesora poszczególnym wykonującym się wątkom. Każdy wątek uzyskuje dostęp do procesora na pewien czas, po czym oddaje procesor innemu wątkowi. Zmiany są tak szybkie, że powstaje wrażenie równoległości.

0

Spróbuj zdjąć synchronized to zobaczysz co się stanie. Generalnie jeżeli używasz synchronized na poziomie metody to do blokowania jest używany obiekt, którego metodę wywołujesz. To oznacza, że pod spodem może zadziałać optymalizator, szczególnie jak masz wersję taką jak @olek1, i stwierdzić - następne N wywołać jest synchronizowane zatem nie opłaca się zdejmować blokady za każdym razem. Niech wykona się to kilka razy więcej, a inni mogą poczekać. W efekcie otrzymujesz sytuację, w której wątek A wykonuje się i razy, bo nie wypada poza blok synchronizacji, a następnie odpala się wątek B i robi to samo. Nawet jak będziesz miał procesor wielordzeniowy to i tak synchronizacja na całym obiekcie spowoduje, że całość działa jak na jednordzeniowym.

Moja propozycja:

  1. Zwiększ ilość kroków w pętli do np 500
  2. Zwiększ ilość wątków.
  3. Zamień int na Integer i:
   public TestSynchro(){
      stanKonta= 0;
    }
  
  public  void inkrementuj(){
        Integer i = stanKonta;
        synchronized(stanKonta){
               stanKonta = i + 1;
        }
        System.out.println("Wykonuje to " + Thread.currentThread().getName() + " Stan konta wynosi: " + stanKonta + " a i wynosi " + i);
    }

I na koniec by zobaczyć, że to działa zdejmij synchronized. Powinno "zgubić" kilka kroków

0

Jakbyś chciał zapewnić taką "uczciwość" w dostępie do bloku (ten co czeka najdłużej, najszybciej go dostanie), to można zastosować Reentrant locka, który został tu bardzo dobrze opisany wraz z innymi metodami synchronizacji:
http://edu.pjwstk.edu.pl/wyklady/zap/scb/W9/W9.htm

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