目录
前言
是什么
格式
同步代码块
同步方法
注意
最后
前言
看多线程的相关书籍的时候, 会经常阅读到一个使用前景, 就是银行的取钱存钱操作.
假设我们使用两个线程来模拟取钱操作, 模拟两个人使用同一个账户并发取钱的问题, 我们都知道存款不可能为负的,
但是往往并发操作的时候, 可能就会导致系统出错导致出现负的数字 (假设一开始都是 200 元余额, 两边同时操作取出 150, 系统可能就会出错).
出现类似这种问题就是缺少同步安全性, 为了解决这个问题, Java 就增进了同步监视器来解决这个, 也就是本文讲的 synchronized 的作用.
是什么
synchronized 是 Java 中的关键字. 同步的意思, 用在解决线程安全问题上. 有添加在方法上, 和直接修饰代码块. 有种保护的作用, 使用修饰之后, 家门上了锁, 别人进不来. 用 synchronized 修饰的方法只允许一个线程执行, 其他线程无法进入该方法.(原子性操作), 银行使用该操作之后, 就会变成一个排队操作一样, 像前言的例子, 就会变成一个人等另一个操作取出 150 之后才可以取钱, 这样就不会出现负的余额.
基本上所有的并发模式 在解决线程冲突的时候, 都是采用序列化访问共享资源的方案. 就是在给定的时间间隔内只允许一个任务访问共享资源.
所以 synchronized 保护的是线程遭受破坏, 必须按照允许的权限进行资源访问.
记得 synchronized 关键字可以修饰方法, 可以修饰代码块, 但不能修饰构造函数, 属性等.
//long 与 double 的操作不是原子的
格式
同步代码块
- //synchronized 代码块
- //obj 对象即表示线程开始执行同步代码块之前, 必须先获得对同步监视器的锁定
- // 步骤: 加锁 -- 修改 -- 释放锁
- synchronized (obj) {
- ...
- }
任何时刻只能有一个线程可以获得对同步监视器的锁定, 当同步代码块执行完成后, 该线程会释放对该同步监视器的锁定. 具体的格式参见上面.
同步方法
- //synchronized 方法, 可以分为静态方法和普通方法
- synchronized void method(){
- ...
- }
- // 等价于
- public void method()
- {
- synchronized(this) {
- // todo
- }
- }
- // 无论哪种形式都可以看做是 "{" 处获取锁,"}" 释放锁
与同步代码块对应, Java 的多线程安全支持还提供了同步方法, 同步方法就是使用 synchronized 关键字来修饰某个方法 (放在权限词的后面即可), 则该方法称为同步方法. 对于同步方法而言, 无须显式指定同步监视器, 同步方法的同步监视器是 this, 也就是该对象本身. 在格式上可以看到一些用法, 但是具体来讲, synchronized 用在方法体上还分为用在普通方法和静态方法两种, 区别在作用锁对象的不同.
修饰普通方法作用的是调用这个方法的对象, 修饰静态方法作用是调用这个类的所有对象.
synchronized static 方法可以在类的范围内防止对 static 数据的并发访问,
使用同步方法可以很方便得实现线程安全的类, 这样类的对象可以被多个线程同时安全得访问.
注意
synchronized 不能被继承.
collection 中的线程不安全的集合可以变成使用 Collections 工具类的, 具体用法语句可以参考 API 文档, 写的还算比较详细.
最后
关于什么使用同步, 也就是上锁, 引用书上的话
如果你在写一个变量, 它可能接下来将被另一个线程读取, 或者正在读取上一个已经被另一个线程写过的变量, 那么你必须使用同步, 并且, 读取线程都必须用相同的监视器锁同步
--Brain Goetz《Java Concurrency in Pactice》的作者
个人学习记录, 有错误欢迎指点, 谢谢! 加油!
来源: https://www.cnblogs.com/yhycoder/p/12267191.html