文档章节

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

 

© 著作权归作者所有

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

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

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

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

欧阳海阳
07/13
0
0
Java synchronized 和 ReentrantLock对比

Java synchronized 和 ReentrantLock对比 前段时间学习了java的线程同步的一些知识,认识到了线程同步的关键字synchronized 和 线程锁java.util.concurrent.lock包下的 ReentrantLock ,下面...

介鬼
06/16
0
0
Java 编程之美:并发编程基础晋级篇

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

gitchat
04/18
0
0
再有人问你synchronized是什么,就把这篇文章发给他。

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

Java填坑之路
08/07
0
0

没有更多内容

加载失败,请刷新页面

加载更多

String转成JSON的实现

String转成JSON 这个依赖很重要,我们将围绕fastjson中的JSONObject这个类来谈转换 欢迎工作一到八年的Java工程师朋友们加入Java高级交流:854630135 本群提供免费的学习指导 架构资料 以及免...

编程SHA
24分钟前
1
0
详解Object.values(),Object.keys(),Object.entries(),Object.create(),includes()

(1)Object.keys() // 返回数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键名。 eg:var obj = {a:1,b:'gy'} Object.keys(obj) // ['a','b'] (2)...

JamesView
47分钟前
2
0
SpringBoot中Mybatis打印sql

application.properties中添加 logging.level.com.example.demo.dao=debug com.example.demo.dao 是对应xml中相应interface层...

writeademo
48分钟前
2
0
Git —— 创建版本库和提交回退版本

二、 创建版本库 版本库又叫做仓库,简单理解就是一个目录,这个目录里面所有的文件都可以被Git管理起来,每个文件的修改、删除,Git都可以跟踪,便于追踪历史与还原。找到一个合适的位置,创...

lwenhao
58分钟前
4
0
guava cache使用介绍

今天在项目中发现大量使用guava cache提供缓存,觉得不错。 jvm堆大小为5G /** * * 占用JVM内存,内部数据结构类似于ConcurrentHashMap。因为JVM堆大小的限制,guava cac...

jack_peng
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部