Java并发编程初级篇(十一):synchronized同步代码块
Java并发编程初级篇(十一):synchronized同步代码块
阿拉德大陆的魔法师 发表于12个月前
Java并发编程初级篇(十一):synchronized同步代码块
  • 发表于 12个月前
  • 阅读 8
  • 收藏 0
  • 点赞 0
  • 评论 0

上一节我们讲解了synchronized方法,它能够保证多个线程并发访问同一个方法的时候,只有一个线程可以访问,其他线程被挂起直到上一个线程执行同步方法完毕。

使用synchronized修饰的方法确实保证了此方法的同步控制,但是这也只是公共变量只在在一个同步方法中被修改才没有问题。当有两个或者以上的方法会修改同一个公共变量的时候,synchronized方法就没有办法保证数据的一致性了,因为其他线程还可以调用两一个方法来修改这个公共变量的值。

所以我们需要使用一个控制类来保证公共变量在多个方法中被访问时只有一个线程能够修改它的值,其他线程都必须挂起等待这个线程的执行完毕。

synchronized (control) {
  doSomething...
}

示例代码:

我们用一个模拟电影院买票的例子,电影院有两部电影,这个电影院有多个售票窗口,每个窗口都可以销售任何一部电影的票,也可以受理任何一部电影的退票业务。

创建Cinema类模拟电影院,在这里我们有两部电影,针对这两部电影有各自独立的售票和退票方法,然后分别使用controlCinema1,controlCinema2来控制这两部电影的售票,退票方法的同步。来保证针对同一部电影在同一时间只有一个线程可以实现售票或者退票操作。

public class Cinema {
    private long vacanciesCinema1;
    private long vacanciesCinema2;
    private final Object controlCinema1, controlCinema2;

    public Cinema(long vacanciesCinema2, long vacanciesCinema1) {
        controlCinema1 = new Object();
        controlCinema2 = new Object();
        this.vacanciesCinema2 = vacanciesCinema2;
        this.vacanciesCinema1 = vacanciesCinema1;
    }

    public boolean sellTickets1(int number) {
        synchronized (controlCinema1) {
            if (vacanciesCinema1 >= number) {
                vacanciesCinema1 -= number;
                return true;
            } else {
                return false;
            }
        }
    }

    public boolean sellTickets2(int number) {
        synchronized (controlCinema2) {
            if (vacanciesCinema2 >= number) {
                vacanciesCinema2 -= number;
                return true;
            } else {
                return false;
            }
        }
    }

    public boolean returnTickets1(int number) {
        synchronized (controlCinema1) {
            vacanciesCinema1 += number;
            return true;
        }
    }

    public boolean returnTickets2(int number) {
        synchronized (controlCinema2) {
            vacanciesCinema2 += number;
            return true;
        }
    }

    public long getVacanciesCinema1() {
        return vacanciesCinema1;
    }

    public long getVacanciesCinema2() {
        return vacanciesCinema2;
    }
}

然后分别模拟两个售票窗口,处理若干售票,退票操作。

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);
    }
}
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);
    }
}

在主方法类中我们创建这两个售票窗口的线程并启动他们,观察最后剩余票数。

public class Main {
    public static void main(String[] args) {
        Cinema cinema = new Cinema(20, 20);

        TicketOffice1 office1 = new TicketOffice1(cinema);
        TicketOffice2 office2 = new TicketOffice2(cinema);

        Thread thread1 = new Thread(office1, "Ticket-Office-1");
        Thread thread2 = new Thread(office2, "TIcket-Office-2");

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

        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.printf("Room1 vacancies: %d\n", cinema.getVacanciesCinema1());
        System.out.printf("Room2 vacancies: %d\n", cinema.getVacanciesCinema2());
    }
}

查看控制台:

Room1 vacancies: 5
Room2 vacancies: 6

 

标签: Java synchronized block
共有 人打赏支持
粉丝 21
博文 91
码字总数 83019
×
阿拉德大陆的魔法师
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: