(二)線程同步_3---在類中使用相互獨立的屬性同步

在類中使用相互獨立的屬性同步

當使用synchronized關鍵字去同步一個代碼塊時,咱們必須傳遞一個引用,一般狀況下能夠使用this關鍵字做爲參數,可是也能夠使用其餘的引用;例如在一個類中有兩個屬性,當多個線程共享這個類時,必須同步這兩個屬性;在同一時間,一個線程訪問其中一個屬性,另一個線程訪問另一個屬性,這樣也是沒問題的;java

在下面的例子中模擬一個電影院,這個電影院有兩個熒幕和兩個獨立的售票窗口,每一個售票窗口對應一個熒幕;相互不影響;因此它們餘票數目也是相互獨立的;ide

動手實驗

1.建立一個cinema,並分別實現兩套相互獨立的售票和返票的方法this

public class Cinema {
    private long vacanciesCinema1;
    private long vacanciesCinema2;

    private final Object controlCinema1,controlCinema2;
    public Cinema(){
        controlCinema1=new Object();
        controlCinema2=new Object();
        vacanciesCinema1=20;
        vacanciesCinema2=20;
    }

    // It uses the controlCinema1 object to control the access to
    // the synchronized block of code
    public boolean sellTickets1 (int number) {
        synchronized (controlCinema1) {
            if (number<vacanciesCinema1) {
                vacanciesCinema1-=number;
                return true;
            } else {
                return false;
            }
        }
    }

    // It uses the controlCinema2 object to control the access to
    // the synchronized block of code
    public boolean sellTickets2 (int number){
        synchronized (controlCinema2) {
            if (number<vacanciesCinema2) {
                vacanciesCinema2-=number;
                return true;
            } else {
                return false;
            }
        }
    }
    // It uses the controlCinema1 object to control the access to
    // the synchronized block of code
    public boolean returnTickets1 (int number) {
        synchronized (controlCinema1) {
            vacanciesCinema1+=number;
            return true;
        }
    }
    // It uses the controlCinema2 object to control the access to
    // the synchronized block of code
    public boolean returnTickets2 (int number) {
        synchronized (controlCinema2) {
            vacanciesCinema2+=number;
            return true;
        }
    }

    public long getVacanciesCinema1() {
        return vacanciesCinema1;
    }
    public long getVacanciesCinema2() {
        return vacanciesCinema2;
    }

}
2.建立兩個售票窗

(1)spa

public class TicketOffice1 implements Runnable {
    private Cinema cinema;
    public TicketOffice1 (Cinema cinema) {
        this.cinema=cinema;
    }
    @Override
    public void run() {
        cinema.sellTickets1(3);
        cinema.sellTickets1(2);
        cinema.sellTickets2(2);
        cinema.returnTickets1(3);
        cinema.sellTickets1(5);
        cinema.sellTickets2(2);
        cinema.sellTickets2(2);
        cinema.sellTickets2(2);
    }
}
(2)
public class TicketOffice2 implements Runnable {
    private Cinema cinema;
    public TicketOffice2(Cinema cinema) {
        this.cinema=cinema;
    }
    @Override
    public void run() {
        cinema.sellTickets2(2);
        cinema.sellTickets2(4);
        cinema.sellTickets1(2);
        cinema.sellTickets1(1);
        cinema.returnTickets2(2);
        cinema.sellTickets1(3);
        cinema.sellTickets2(2);
        cinema.sellTickets1(2);
    }
}
3.Main方法

public class Main {
    public static void main(String[] args) {
        Cinema cinema=new Cinema();
        TicketOffice1 ticketOffice1=new TicketOffice1(cinema);
        Thread thread1=new Thread(ticketOffice1,"TicketOffice1");

        TicketOffice2 ticketOffice2=new TicketOffice2(cinema);
        Thread thread2=new Thread(ticketOffice2,"TicketOffice2");

        thread1.start();
        thread2.start();

        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.printf("Room 1 Vacancies: %d\n",cinema.getVacanciesCinema1());
        System.out.printf("Room 2 Vacancies: %d\n",cinema.getVacanciesCinema2());
    }
}

運行結果:

Room 1 Vacancies: 5
Room 2 Vacancies: 6
線程

要點

JVM確保一個線程只能訪問其中一個被同步的同一個對象的代碼塊(這裏是說的是對象,而不是類),在這個例子中,vacanciesCinema1,vacanciesCinema2這兩個對象控制訪問對應的屬性,因此每次只能有一個線程修改一個屬性;兩個線程也能夠同時運行,分別修改對應的屬性;code

相關文章
相關標籤/搜索