synchronized

神圣兽国窝窝乡独行侠發表於2024-10-27
靜態方法跟普通的synchronized方法有所區別,需要特別注意的是,雖然靜態的同步方法僅允許同時只有一個執行緒參與訪問,但與此同時其他執行緒依然可以訪問另一個由synchronized修飾的非靜態方法。在這裡,雖然兩個執行緒都是訪問同一個物件例項上的方法(其中一個是靜態方法,而另一個不是),但是這兩個方法卻繫結了不同的物件。因此當透過這兩個方法修改同一份共享資料時,可能會帶來資料一致性的錯誤。造成該錯誤的原因是,當程式由synchronized修飾的靜態方法呼叫時,此時方法所關聯的物件是類物件而並非該類的例項物件

金額類

package parkingsystem;

public class ParkingCash {
    private static final int cost = 2;

    private long cash;

    public ParkingCash() {
        cash = 0;
    }

    public synchronized void vehiclePay() {
        cash += cost;
    }

    public void close() {
        System.out.printf("Closing accounting");
        long totalAmmount;
        synchronized (this) {
            totalAmmount = cash;
            cash = 0;
        }
        System.out.printf("The total amount is : %d",
                totalAmmount);
    }
}

狀態類

package parkingsystem;

public class ParkingStats {
    private final Object controlCars, controlMotorcycles;
    private long numberCars;
    private long numberMotorcycles;
    private ParkingCash cash;

    public ParkingStats(ParkingCash cash) {
        numberCars = 0;
        numberMotorcycles = 0;
        controlCars = new Object();
        controlMotorcycles = new Object();
        this.cash = cash;
    }

    public void carComeIn() {
        synchronized (controlCars) {
            numberCars++;
        }
    }

    public void carGoOut() {
        synchronized (controlCars) {
            numberCars--;
        }
        cash.vehiclePay();
    }

    public void motoComeIn() {
        synchronized (controlMotorcycles) {
            numberMotorcycles++;
        }
    }

    public void motoGoOut() {
        synchronized (controlMotorcycles) {
            numberMotorcycles--;
        }
        cash.vehiclePay();
    }

    public long getNumberCars() {
        return numberCars;
    }

    public long getNumberMotorcycles() {
        return numberMotorcycles;
    }
}

模擬停車行為類

package parkingsystem;

import java.util.concurrent.TimeUnit;

public class Sensor implements Runnable {
    private ParkingStats stats;

    public Sensor(ParkingStats stats) {
        this.stats = stats;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            stats.carComeIn();
            stats.carComeIn();
            try {
                TimeUnit.MILLISECONDS.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            stats.motoComeIn();
            try {
                TimeUnit.MILLISECONDS.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            stats.motoGoOut();
            stats.carGoOut();
            stats.carGoOut();
        }
    }
}

測試類Main

package parkingsystem;

public class Main {
    public static void main(String[] args) {
        ParkingCash cash = new ParkingCash();
        ParkingStats stats = new ParkingStats(cash);

        System.out.printf("Parking Simulator\n");
        int numberSensors = 2 * Runtime.getRuntime().availableProcessors();
        Thread threads[] = new Thread[numberSensors];
        for (int i = 0; i < numberSensors; i++) {
            Sensor sensor = new Sensor(stats);
            Thread thread = new Thread(sensor);
            thread.start();
            threads[i] = thread;
        }

        for (int i = 0; i < numberSensors; i++) {
            try {
                threads[i].join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        System.out.printf("Number of cars: %d\n",
                stats.getNumberCars());
        System.out.printf("Number of motorcycles: %d\n",
                stats.getNumberMotorcycles());
        cash.close();
    }
}

相關文章