Adam Lipowski

Problemy ze współbieżnością

Jeżeli kilka wątków może jednocześnie działać na tym samym obiekcie wówczas mogą pojawiać się pewne nieprzewidywane i często niepożądane efekty.
Rozważmy  następujący przykład:

class Balance {
    private int number = 0;
    public int balance() {
       number++;
      number--;
    return number;
  } 
}  

Wydaje się, że jakiekolwiek  wielokrotne wywołanie metody balance() na rzecz dowolnego obiektu klasy Balance zawsze zwróci 0. Okazuje się jednak, że wielokrotne wywołanie tej metody na rzecz tego samego obiektu może dawać inny wynik. Sytuacja taka może powstać wtedy gdy działający wątek wykona instrukcję number++ i zostanie wywłaszczony. W efekcie number=1.

Przykład:
Aplet gdzie w kilku różnych wątkach wielokrotnie wywoływana jest metoda balance() na rzecz tego samego obiektu. Jeżeli wynik zwracany przez balance() będzie różny od zera to wątek jest przerywany.

Aplet

import java.awt.*;
import java.applet.*;
import java.awt.event.*;
class Balance {
 
  private int number = 0;
 
  public int balance() {
    number++;
    number--;
    return number;
  } 
 


class BalanceThread extends Thread {
 
  private Balance b;  // referencja do obiektu klasy Balance
  private int count;  // liczba pwotórzeń pętli w metodzie run
   
  public BalanceThread(String name, Balance b, int count) {
    super(name);
    this.b = b;
    this.count = count;
    start();
  } 

  public void run() {
    int wynik = 0;
//    synchronized(b) {
      for (int i = 0; i < count; i++) {
        wynik = b.balance(); 
        if (wynik != 0) break;
      }
//    }
     Thread.currentThread().setName("wynik="+wynik);   
  }


public class BalanceTest extends Applet implements ActionListener{
    int tnum=5;   // liczba wątkow
    Button przycisk = new Button("Start");
    TextField t1 = new TextField("10000000");
    Label [] la = new Label[tnum];
    Label status = new Label("status");
    Panel pan = new Panel();
    public void init(){
    add(new Label("# iteracji"));
    add(t1);
    t1.addActionListener(this);
    add(przycisk);
    przycisk.addActionListener(this);                 
for(int i=0;i<tnum;i++){la[i]=new Label("label "+i); pan.add(la[i]);}
    pan.setLayout(new GridLayout(5,1));
    add(pan);
    add(status);
  } // koniec init

  public void actionPerformed(ActionEvent e){
  int count=10000000;
if(e.getSource()==t1){count=Integer.parseInt(t1.getText());
}
else{
status.setText("liczę");
// Tworzymy obiekt klasy balance  
 Balance b = new Balance();   
   // Tworzymy i uruchamiamy wątki
    Thread[] thread = new Thread[tnum];
    for (int i = 0; i < tnum; i++)
      thread[i] = new BalanceThread("W"+(i+1), b, count);

   
    // czekaj na zakończenie wszystkich wątków
    try {
      for (int i = 0; i < tnum; i++) {thread[i].join();
       la[i].setText(thread[i].getName());
       thread[i]=null;}
    } catch (InterruptedException exc) {
      System.exit(1);
    } 
status.setText("koniec");
  }//koniec if'a
  }  // koniec actionPerformed

}       //koniec BalanceTest