wątki, działanie w nieskończoność

0

Cześć :)
Popatrzcie na kod:

package concurrency;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.*;

class Pair { // Niezabezpieczona
  private int x, y;
  public Pair(int x, int y) {
    this.x = x;
    this.y = y;
  }
  public Pair() { this(0, 0); }
  public int getX() { return x; }
  public int getY() { return y; }
  public void incrementX() { x++; }
  public void incrementY() { y++; }
  public String toString() {
    return "x: " + x + ", y: " + y;
  }
  public class PairValuesNotEqualException
  extends RuntimeException {
    public PairValuesNotEqualException() {
      super("Wartoci pary s¹ nierówne: " + Pair.this);
    }
  }
  // Niezmiennik -- obie zmienne musz¹ byæ równe:
  public void checkState() {
    if(x != y)
      throw new PairValuesNotEqualException();
  }
}

// Ochrona klasy Pair w klasie zabezpieczonej na
// okolicznoæ pracy wielow¹tkowej:
abstract class PairManager {
  AtomicInteger checkCounter = new AtomicInteger(0);
  protected Pair p = new Pair();
  private List<Pair> storage =
    Collections.synchronizedList(new ArrayList<Pair>());
  public synchronized Pair getPair() {
    // Utworzenie kopii w celu zabezpieczenia orygina³u:
    return new Pair(p.getX(), p.getY());
  }
  // Zak³adamy, ¿e to d³ugotrwa³a operacja
  protected void store(Pair p) {
    storage.add(p);
    try {
      TimeUnit.MILLISECONDS.sleep(50);
    } catch(InterruptedException ignore) {}
  }
  public abstract void increment();
}

// Synchronizacja ca³ej metody:
class PairManager1 extends PairManager {
  public synchronized void increment() {
    p.incrementX();
    p.incrementY();
    store(getPair());
  }
}

// Zastosowanie sekcji krytycznej:
class PairManager2 extends PairManager {
  public void increment() {
    Pair temp;
    synchronized(this) {
      p.incrementX();
      p.incrementY();
      temp = getPair();
    }
    store(temp);
  }
}

class PairManipulator implements Runnable {
 private PairManager pm;
  public PairManipulator(PairManager pm) {
    this.pm = pm;
  }
  public void run() {
    while(true){
        
      pm.increment();
        }
    }
  public String toString() {
    return "Para: " + pm.getPair() +
      " licznik = " + pm.checkCounter.get();
  }
}

class PairChecker implements Runnable {
  private PairManager pm;
  public PairChecker(PairManager pm) {
    this.pm = pm;
  }
  public void run() {
    while(true) {
      pm.checkCounter.incrementAndGet();
      pm.getPair().checkState();
    }
  }
}

public class CriticalSection {
  // test obu rozwi¹zañ:
  static void
  testApproaches(PairManager pman1, PairManager pman2) {
    ExecutorService exec = Executors.newCachedThreadPool();
    PairManipulator
      pm1 = new PairManipulator(pman1),
      pm2 = new PairManipulator(pman2);
    PairChecker
      pcheck1 = new PairChecker(pman1),
      pcheck2 = new PairChecker(pman2);
    exec.execute(pm1);
    exec.execute(pm2);
    exec.execute(pcheck1);
    exec.execute(pcheck2);
    try {
      TimeUnit.MILLISECONDS.sleep(100);
    } catch(InterruptedException e) {
      System.out.println("Uspienie przerwane");
    }
    System.out.println("pm1: " + pm1 + "\npm2: " + pm2);
    System.exit(0);
  }
  public static void main(String[] args) {
    PairManager
      pman1 = new PairManager1(),
      pman2 = new PairManager2();
    testApproaches(pman1, pman2);
  }
} /* Output: (Sample)
pm1: Para: x: 15, y: 15 licznik = 272565
pm2: Para: x: 16, y: 16 licznik = 3956974
*///:~

Dlaczego ten program nie daje żadnych reultatów na ekran?
Co mnie jednak najbardziej dziwi?
To, że zmiana metody run() w PairManipulator na:

  public void run() {
    while(true){
        System.out.println("c");
      pm.increment();
        }
    }

( dodana tylko linijka wypisywania sprawi, że nastąpi przerwanie i rezultat na ekranie:

 
pm1: Para: x: 2, y: 2 licznik = 1110
pm2: Para: x: 3, y: 3 licznik = 3835311

Dlaczego tak się dzieje?

1

U mnie dziala za kazdym razem. Mozesz napisac na jakiej konfiguracji to odpalasz?
A moze uruchamiasz ten kod na procesorze z modelem pamieci innym niz TSO (arm, ppc, sparc, dec, alpha)?

0

Architecture: x86_64
Więc raczej też model TSO.
Myślę, że to może być przyczyna, że procesor jest w technologii HT, czyli realizuje dwa wątki na jednym rdzeniu, któych jest cztery. ( Core i7)
Hmmm.. w takim razie pytanie brzmi inaczej.
Dlaczego tak się dzieje oraz dlaczego samo dodanie wypisywania na ekran poprawia?

1
mir napisał(a):

Dlaczego tak się dzieje oraz dlaczego samo dodanie wypisywania na ekran poprawia?

Niespecjalnie moge sie do tego odniesc, poniewaz u mnie kod dziala bez przerwan. Jestes absolutnie pewien ze wpadasz gdzies w catch(InterruptedException) ?

0

dobra, ja chyba czegoś nie rozumiem,
Rozważmy:

 public void run() {
    while(true) {
      synchronized(this) {
        ++number;
      }
      print(this + " Razem: " + count.increment());
      try {
        TimeUnit.MILLISECONDS.sleep(100);
      } catch(InterruptedException e) {
        print("przerwano upienie");
      }
    }
    print("Zatrzymywanie: " + this);
  }

Noi załóżmy, że odpalamy wątek z puli.
Co się kolejno dzieje. Po prostu nie rozumiem chyba samego sleep(), jak on w istocie działa dla samego wątku, co się dzieje po upłynięciu tego czasu oraz jaki to ma wpływ na inne wątki.
pozdrawiam :)

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