Współbieżność, pomoc przy programie

0

Witam

Potrzebuję pomocy przy programie, w pewnym momencie się zawiesza. Lisitngu nie wrzucą bo to ponad 400 linii, ale jeśli ktoś chciałby mi pomóc to mogę wysłać. Program robię na podstawie TIJ, ale w jednym miejscu i w książka nie pomaga.

Pozdrawiam

0

A może ktoś <ort>napiszę </ort>mi <ort>napiszę </ort>czy istnieją jakieś narzędzia <ort>nie odpłatne </ort>przy pomocy<ort>, </ort>których mogę wykryć błędy programu współbieżnego, używam NetBeans, może są jakieś wtyczki, jednak ja nic nie znalazłem. Próbowałem zainstalować findbug'a<ort> </ort>ale bezskutecznie, chyba link już jest martwy.

0

Wszystkie klasy mam w jednym pliku, więc wystarczy wrzucić, włączyć i przejrzeć listing:

import java.text.SimpleDateFormat;
import java.util.concurrent.*;
import java.util.*;

class Car {
  private final int id;
  private boolean
    cleaned = false, washed = false, waxed = false,
    needCleaning = false, needWashing = false, needWaxing = false,
    cleaningInProgress = false, washingInProgress = false, waxingInProgress = false,
    cleaningDone = false, washingDone = false, waxingDone = false;
  private final String arrivedTime;
  private static Random rand = new Random();
  public Car(int idn)  { 
      id = idn;
      needCleaning = rand.nextBoolean();
      needWashing = rand.nextBoolean();
      needWaxing = rand.nextBoolean();
      arrivedTime = DateUtils.now();
      cleaningDone = ! needCleaning;
      washingDone = ! needWashing;
      waxingDone = ! needWaxing;

  }
  public Car()  {
      id = -1;
      arrivedTime = DateUtils.now();
  }
  public synchronized int getId() { return id; }

  public synchronized void waxing() {
      waxingInProgress = true;
  }

  public synchronized void cleaning() {
      cleaningInProgress = true;
  }

  public synchronized void washing() {
      washingInProgress = true;
  }

  public synchronized void waitForWashing() throws InterruptedException {
      while(! cleaningDone) {
          wait();
      }
  }

  public synchronized void waitForWaxing() throws InterruptedException {
      while (! washingDone || ! cleaningDone) {
          wait();
      }
  }

  public synchronized void waitIfAnyServiceIsProcessingCar() throws InterruptedException {
      while (washingInProgress || cleaningInProgress || waxingInProgress) {
          wait();
      }
  }

  public synchronized void waitForAllServiceFinished() throws InterruptedException {
          while (! cleaningDone || ! washingDone || ! waxingDone) {
              wait();
          }
  }

  public synchronized void cleaned() {
      cleaned = true;
      cleaningInProgress = false;
      cleaningDone = true;
      notifyAll();
  }
  public synchronized void waxed() {
      waxed = true;
      waxingInProgress = false;
      waxingDone = true;
      notifyAll();
  }
  public synchronized void washed() {
      washed = true;
      washingInProgress = false;
      washingDone = true;
      notifyAll();
  }

  public synchronized boolean needCleaning() {
      return needCleaning;
  }

  public synchronized boolean needWashing() {
      return needWashing;
  }

   public synchronized boolean needWaxing() {
      return needWaxing;
  }

    @Override
    public synchronized String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("------------------------------------");
        builder.append("\n");
        builder.append("Informacje na temat obsługi pojazdu o id: " + id);
        builder.append("\n");
        builder.append("Czas przybycia: " + arrivedTime);
        builder.append("\n");
        builder.append("Czas odjazdu: " + DateUtils.now());
        builder.append("\n");
        builder.append("------------------");
        builder.append("\n");
        builder.append("Zamówiony pakiet: ");
        builder.append("\n");
        builder.append("------------------");
        builder.append("\n");
        builder.append("Sprzątanie: ");
        builder.append(needCleaning ?  "Tak"  : "Nie");
        builder.append("\n");
        builder.append("Mycie: ");
        builder.append(needWashing ?  "Tak"  : "Nie");
        builder.append("\n");
        builder.append("Woskowanie: ");
        builder.append(needWaxing ?  "Tak"  : "Nie");
        builder.append("\n");
        builder.append("------------------");
        builder.append("\n");
        builder.append("Wykonany serwis: ");
        builder.append("\n");
        builder.append("------------------");
        builder.append("\n");
        builder.append("Sprzątanie: ");
        builder.append(cleaned ?  "Tak"  : "Nie");
        builder.append("\n");
        builder.append("Mycie: ");
        builder.append(washed ?  "Tak"  : "Nie");
        builder.append("\n");
        builder.append("Woskowanie: ");
        builder.append(waxed ?  "Tak"  : "Nie");
        builder.append("\n");
        builder.append("------------------");
        builder.append("\n");
        builder.append("Pojazd o id :" + id + " opuścił myjnię.");
        builder.append("\n");
        builder.append("------------------------------------");
        builder.append("\n");
        return builder.toString();
    }
}

class CarQueue extends LinkedBlockingQueue<Car> {
}

class CarWashEntrance implements Runnable {
  private CarQueue carQueue;
  private int counter = 0;
  private boolean isOpen = false;
  public CarWashEntrance(CarQueue cq) { carQueue = cq; }
  public void run() {
   open();
    try {
      while(isOpen()) {
        TimeUnit.MILLISECONDS.sleep(1500);
        Car c = new Car(counter++);
        System.out.println("Pojazd o id: " + c.getId() + " znajduje się w kolejce do myjnii.");
        carQueue.put(c);
        
      }
    } catch(InterruptedException e) {
    }
    System.out.println("Brama wjazdowa została zamknięta.");
  }
  public synchronized boolean isOpen() { return isOpen; }
  public synchronized void open() {
      isOpen = true;
      System.out.println("Brama wjazdowa została otwarta.");
  }
  public synchronized void close() { isOpen = false; }
}

class CarWashLine implements Runnable {
  private CarQueue waitingQueue, finishingQueue, processingQueue;
  private Car car;
  private ServicePool servicePool;
  public CarWashLine(CarQueue cq, CarQueue fq, ServicePool rp){
    waitingQueue = cq;
    finishingQueue = fq;
    processingQueue = new CarQueue();
    servicePool = rp;
  }
  public CarQueue getProcessingQueue() { return processingQueue; }
  public CarQueue getFinishingQueue() { return finishingQueue; }

  public Car car() { return car; }
  public void run() {
    try {
      while(!Thread.interrupted()) {
        car = waitingQueue.take();
        processingQueue.put(car);
        System.out.println("Rozpoczęto obsługę pojazdu o id: " + car.getId());
        servicePool.hire(CleanupService.class, this);
        servicePool.hire(WashService.class, this);
        servicePool.hire(WaxService.class, this);
      }
    } catch(InterruptedException e) {}

  }

  public synchronized boolean areAnyCarsInside() {
      return processingQueue.size() > 0 || waitingQueue.size() > 0;
  }

  public void showWaitingCarsAmount() {
      System.out.println("Pozostało: " + (processingQueue.size() + waitingQueue.size()) + " oczekujących aut.");
  }
}

class CarWashExit implements Runnable {
  private CarQueue carQueue;
  public CarWashExit(CarQueue cq) { carQueue = cq; }
  public void run() {
    System.out.println("Brama wyjazdowa zostaje otwarta.");
    try {
      while(!Thread.interrupted()) {
        Car c = carQueue.take();
        System.out.println("W bramie wyjazdowej jest pojazd" + c.getId());
        c.waitForAllServiceFinished();
        System.out.println(c);
      }
    } catch(InterruptedException e) {}
    System.out.println("Brama wyjazdowa zostaje zamknięta.");
  }
}

abstract class Service implements Runnable {
  private ServicePool pool;
  public Service(ServicePool p) { pool = p; }
  protected CarWashLine line;
  protected String serviceName;
  public Service assignLine(CarWashLine carWashLine) {
    this.line = carWashLine;
    return this;
  }
  private boolean inUse = false;
  public synchronized void use() {
    inUse = true;
    notifyAll();
  }

  abstract protected void performService();
  
  public void run() {
    System.out.println(this + " zostało otwarte.");
    try {
      powerDown();
      while(!Thread.interrupted()) {
        performService();
        powerDown();
      }
    } catch(InterruptedException e) {}
    System.out.println(this + " zostało zamknięte.");
  }
  private synchronized void
  powerDown() throws InterruptedException {
    inUse = false;
    line = null;
    pool.release(this);
    while(inUse == false)  // Power down
      wait();
  }
    @Override
    public synchronized String toString() {
        return "Stanowisko <" + serviceName + "> ";
    }
}

class CleanupService extends Service {
  public CleanupService(ServicePool pool) {
        super(pool);
        serviceName = "Sprzątające";
  }
  protected void performService() {
        try {
            Car car = line.car();
            if (car.needCleaning()) {
                car.cleaning();
                System.out.println(this + " sprzątanie pojazdu o id: " + car.getId() + " w toku...");
                TimeUnit.SECONDS.sleep(4);
                System.out.println(this + " sprzątanie pojazdu o id: " + car.getId() + " zakończone.");
                car.cleaned();
                if (! car.needWashing() && ! car.needWaxing()) {
                    line.getProcessingQueue().remove(car);
                    line.getFinishingQueue().put(car);
                }
            }
        } catch (InterruptedException ex) {
        }
  }
}

class WashService extends Service {
  public WashService(ServicePool pool) {
        super(pool);
        serviceName = "Myjące";
  }
  protected void performService() {
        try {
            Car car = line.car();
            if (car.needWashing()) {
                car.waitForWashing();
                car.washing();
                System.out.println(this + " mycie pojazdu o id: " + car.getId() + " w toku...");
                TimeUnit.SECONDS.sleep(1);
                System.out.println(this + " mycie pojazdu o id: " + car.getId() + " zakończone.");
                car.washed();
                if (! car.needWaxing()) {
                    line.getProcessingQueue().remove(car);
                    line.getFinishingQueue().put(car);
                }
            } 
        } catch (InterruptedException ex) {
        }
  }
}

class WaxService extends Service {
  public WaxService(ServicePool pool) {
        super(pool);
        serviceName = "Woskujące";
  }
  protected void performService() {
        try {
            Car car = line.car();
            if (car.needWaxing()) {
                car.waitForWaxing();
                car.waxing();
                System.out.println(this + " woskowanie pojazdu o id: " + car.getId() + " w toku...");
                TimeUnit.SECONDS.sleep(1);
                System.out.println(this + " woskowanie pojazdu o id: " + car.getId() + " zakończone.");
                car.waxed();
                line.getProcessingQueue().remove(car);
                line.getFinishingQueue().put(car);
            }
        } catch (InterruptedException ex) {
        }
  }
}

class ServicePool {
  private Set<Service> pool = new HashSet<Service>();
  public synchronized void add(Service s) {
    pool.add(s);
    notifyAll();
  }
  public synchronized void
  hire(Class<? extends Service> serviceType, CarWashLine line)
  throws InterruptedException {
    for(Service s : pool)
      if(s.getClass().equals(serviceType)) {
        pool.remove(s);
        s.assignLine(line);
        s.use(); 
        return;
      }
    wait();
    hire(serviceType, line); 
  }
  public synchronized void release(Service r) { add(r); }
}


class DateUtils {
  public static final String DATE_FORMAT_NOW = "HH:mm:ss";

  public static String now() {
    Calendar cal = Calendar.getInstance();
    SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT_NOW);
    return sdf.format(cal.getTime());

  }
}

public class CarWash {
  public static void main(String[] args) throws Exception {
    System.out.println(DateUtils.now().toString() + " rozpoczęcie pracy myjni...");
    CarQueue waitingQueue = new CarQueue(),
             finishingQueue = new CarQueue();
    ExecutorService exec = Executors.newCachedThreadPool();
    ServicePool servicePool = new ServicePool();
    CarWashEntrance entrance = new CarWashEntrance(waitingQueue);
    CarWashLine line = new CarWashLine(
      waitingQueue, finishingQueue, servicePool);
    exec.execute(new CleanupService(servicePool));
    exec.execute(new WashService(servicePool));
    exec.execute(new WaxService(servicePool));
    exec.execute(line);
    exec.execute(new CarWashExit(finishingQueue));
    exec.execute(entrance);
    TimeUnit.SECONDS.sleep(20);
    entrance.close();
    while (line.areAnyCarsInside()) {}
    exec.shutdownNow();
    System.out.println(DateUtils.now().toString() + " zakończenie pracy myjni.");
    line.showWaitingCarsAmount();
    System.exit(0);
  }
}

0

Problemy:

Nie wiem dlaczego pojazdy opuszczają myjnię dwukrotnie (często, klasa CarWashExit), no i nie wiem czemu zawiesza się to wszystko w pewnym miejscu. Wcześniej używałem wg TIJ CyclicBarrier ale to psuje całe założenie tego programu, sorry za multi posty, ale już nie myślę.

0

Super-pachnie baaardzo komercyjnym użyciem i wszystko by było Ok gdybyś ze swojej strony trochę włożył wysiłku. Masz IDE to masz debug...zaznaczaj znaczące operacje i patrz co isę dzieje krok po kroku....daj jakaś kontrole wyjątków (chociaż jak odpaliłem program to nie było błędów).
On nie jest zawieszony tylko czeka na synchronizację....rób break pointy i debug odpal...a tak w ogóle to jak jest 400linni kodu to po co go cały wklejasz-obcinaj trochę...ten kod da się w kilkunastu liniach dla fazy testów...debug debug debug

0

Dzięki za odpowiedź.

Komercyjne? To żadna komercja. To zadanie ze studiów jest, oparłem je na połączenie kilku programów z TIJ, gdzie przykłady są znakomite i może dlatego tak wygląda.

A kod cały wrzuciłem tylko dlatego żeby każdy mógł zobaczyć jak działa, jeśli będzie chciał.

W każdym razie zmieniłem trochę program i już prawie wszystko działa, ale mam problem z wykończeniem programu.

Program działa przez jakiś czas, po upływie danego czasu brama wjazdowa zostaje zamknięta. No ale jeśli w kolejkach do poszczególnych stacji są auta no to trzeba poczekać aż wszystkie wyjadą i wtedy wątki są zabijane i pokazywany jest komunikat że stanowisko zostało zamknięte (w przechwyceniu InterruptedException)

Samo sprawdzenie stanu kolejek działa, z tym że jeśli właśnie jest obsługiwany jakiś pojazd, może dojść do sytuacji, że w kolejce już nic nie ma i zostanie pokazany komunikat:

Stanowisko X rozpoczęło mycie pojazdu Y
Stanowisko X zostało zamknięte.

A więc tak jakby pojazd będzie myty na zawsze, chciałem to zmienić więc dodałem jeszcze jedną flagę

inUse. Kod klasy bazowej dla stanowisk poniżej:

public abstract class Station implements Runnable {
    protected LinkedBlockingQueue<Vehicle> vehicles
            = new LinkedBlockingQueue<Vehicle>();

    protected MyDialog view;

    protected MyDialog exit;

    private boolean inUse = false;

    public synchronized void setStatus(boolean status) {
            this.inUse = status;
    }

    public synchronized boolean isInUse() {
        return this.inUse;
    }

    public Station(MyDialog panel, MyDialog exit) {
        this.view = panel;
        this.exit = exit;
    }

    public synchronized void addVehicle(Vehicle v) {
        if (this.vehicles.size() < 15) {
            this.vehicles.add(v);
        }
        else {
            this.view.append("W kolejce czeka 15 samochodów, nie ma więcej miejsc.");
            this.exit.append(v + " opuszcza myjnię.");
        }
    }

    public synchronized boolean areAnyCarsAwaits() {
        return this.vehicles.size() > 0 || this.isInUse();
    }

    public void run()  {
        this.view.append("Stanowisko zostało otwarte.");
        try {
            while(! Thread.interrupted()) {
                this.setStatus(true);
                this.serve();
                this.setStatus(false);
            }
        } catch(InterruptedException ex)  {
             this.view.append("Stanowisko zostało zamknięte.");
        }

    }
    protected abstract void serve() throws InterruptedException;
}

Metodą areAnyCarsAwaits() sprawdzam czy można bezpiecznie zamknąć stanowisko, jednak do tego nie dochodzi. Gdy kolejka jest pusta debug pokazuje ze inUse jest zawsze true, więc wątek nigdy nie zostaje zabity, a ja nie otrzymuje na wyjście komunikatu "Stanowisko zostało zamknięte."

Przykładowa implementacja metody serve() wygląda tak, ale chyba to nie ma w tym nic do gadania:

    protected void serve() throws InterruptedException {
        Vehicle v = this.vehicles.take();
        this.view.append("Sprzątanie " + v + " w toku...");
        TimeUnit.SECONDS.sleep(3);
        this.view.append("Sprzątanie " + v + " zostało zakończone.");
        v.doCleaning();
        if (v.washed() && v.cleaned() && v.polished())  {
            this.exit.append(v + " opuszcza myjnię...");
        }
    }

Doradzi ktoś?

Pozdrawiam

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