文档章节

Java并发编程初级篇(十一):synchronized同步代码块

阿拉德大陆的魔法师
 阿拉德大陆的魔法师
发布于 2016/11/24 11:49
字数 727
阅读 14
收藏 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

 

© 著作权归作者所有

共有 人打赏支持
阿拉德大陆的魔法师
粉丝 26
博文 91
码字总数 83019
作品 0
西城
程序员
私信 提问
Java多线程学习(二)synchronized关键字(2)

系列文章传送门: Java多线程学习(一)Java多线程入门 Java多线程学习(二)synchronized关键字(1) java多线程学习(二)synchronized关键字(2) Java多线程学习(三)volatile关键字 Ja...

一只蜗牛呀
2018/04/16
0
0
关于Java里面多线程同步的一些知识

# 关于Java里面多线程同步的一些知识 对于任何Java开发者来说多线程和同步是一个非常重要的话题。比较好的掌握同步和线程安全相关的知识将使得我们则更加有优势,同时这些知识并不是非常容易...

欧阳海阳
2018/07/13
0
0
再有人问你synchronized是什么,就把这篇文章发给他。

在《深入理解Java虚拟机》中,有这样一段话: synchronized关键字在需要原子性、可见性和有序性这三种特性的时候都可以作为其中一种解决方案,看起来是“万能”的。的确,大部分并发控制操作...

Java填坑之路
2018/08/07
0
0
Java程序员从笨鸟到菜鸟之(十一)多线程讲解

本文来自:曹胜欢博客专栏。转载请注明出处:http://blog.csdn.net/csh624366188 多线程是java应用程序的一个特点,掌握java的多线程也是作为一java程序员必备的知识。多线程指的是在单个程序...

长平狐
2012/11/12
80
0
Java 编程之美:并发编程基础晋级篇

本文来自作者 加多 在 GitChat 上分享 「Java 并发编程之美:并发编程基础晋级篇」 编辑 | Mc Jin 借用 Java 并发编程实践中的话,编写正确的程序并不容易,而编写正常的并发程序就更难了! ...

gitchat
2018/04/18
0
0

没有更多内容

加载失败,请刷新页面

加载更多

mysql grant 用户权限总结

用户权限管理主要有以下作用: 1. 可以限制用户访问哪些库、哪些表 2. 可以限制用户对哪些表执行SELECT、CREATE、DELETE、DELETE、ALTER等操作 3. 可以限制用户登录的IP或域名 4. 可以限制用...

Airship
14分钟前
1
0
RabbitMQ学习(3)

1. 消费端 1. 消费端通过推模式或者拉模式从RabbitMQ中获取并消费消息,当消费者确认处理消息后,可以手动确认消息已被接收,然后就会将该消息从RabbitMQ的队列中标记再清除,消费者端还可以...

江左煤郎
25分钟前
1
0
linux mysql(5.7)开启慢查询

一、有3个配置需要设置, 1:相关开关 2:日志目录文件 3:慢查询的时间限制 二、设置完之后重启mysql service mariadb restart 三、重启后做个测试 连接mysql 并查询: select sleep(6); 四...

chro008
33分钟前
1
0
选择IDC机房、选择硬件、上架服务器、装系统

选择IDC机房 当业务量比较大的时候,往往选用IDC而不是公有云来跑业务。 IDC机房的服务一般分为两种 需要我们自己购买服务器和网络设备,托管到IDC机房。IDC机房会提供布线、巡检、硬件操作等...

李超小牛子
34分钟前
2
0
《傲慢与偏见》的读书笔记与读后感作文2400字

《傲慢与偏见》的读书笔记与读后感作文2400字: 作者:孙苑馨;笔者按:读书这个习惯是我爸妈养出来的。小时候父母赚的钱除了吃饭穿衣剩下的就是买书了,他们除了买各种新鲜出版的文艺派图书...

原创小博客
43分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部