新闻资讯

新闻资讯 行业动态

浅谈synchronized

编辑:006     时间:2020-02-14

前言

看多线程的相关书籍的时候,会经常阅读到一个使用前景,就是银行的取钱存钱操作。
假设我们使用两个线程来模拟取钱操作,模拟两个人使用同一个账户并发取钱的问题,我们都知道存款不可能为负的,
但是往往并发操作的时候,可能就会导致系统出错导致出现负的数字(假设一开始都是200元余额,两边同时操作取出150,系统可能就会出错)。
出现类似这种问题就是缺少同步安全性,为了解决这个问题,Java就增进了同步监视器来解决这个,也就是本文讲的synchronized的作用。

是什么

synchronized是Java中的关键字。同步的意思,用在解决线程安全问题上。有添加在方法上,和直接修饰代码块。有种保护的作用,使用修饰之后,家门上了锁,别人进不来。用synchronized修饰的方法只允许一个线程执行,其他线程无法进入该方法。(原子性操作),银行使用该操作之后,就会变成一个排队操作一样,像前言的例子,就会变成一个人等另一个操作取出150之后才可以取钱,这样就不会出现负的余额。

  1. 基本上所有的并发模式 在解决线程冲突的时候,都是采用序列化访问共享资源的方案。就是在给定的时间间隔内只允许一个任务访问共享资源。
所以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数据的并发访问,

使用同步方法可以很方便得实现线程安全的类,这样类的对象可以被多个线程同时安全得访问。

注意

  1. synchronized不能被继承。
  2. collection中的线程不安全的集合可以变成使用Collections工具类的,具体用法语句可以参考API文档,写的还算比较详细。

最后

  1. 关于什么使用同步,也就是上锁,引用书上的话

    如果你在写一个变量,它可能接下来将被另一个线程读取,或者正在读取上一个已经被另一个线程写过的变量,那么你必须使用同步,并且,读取线程都必须用相同的监视器锁同步

    ——Brain Goetz《Java Concurrency in Pactice》的作者

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。

回复列表