标签:共享数据 类锁 style 简单的 指令 关键字 exit 存在 额外
相信熟悉java的同学对synchronized关键字也是非常熟悉了,似乎只要在涉及到线程安全的问题的问题中,加上synchronized关键字就对了!
比如下面这个我们比较常见的代码,懒汉式单例模式:
public class LazySimpleSinglethon { private static LazySimpleSinglethon singlethon = null; private LazySimpleSinglethon(){} public synchronized tatic LazySimpleSinglethon getInstance(){ if(singlethon==null){ //如果不加synchronizde会存在线程安全问题 singlethon = new LazySimpleSinglethon(); } return singlethon; } }
好,问题来了,为什么会有线程安全问题?什么是线程安全问题?《Java Concurrency In Practice》一书的作者Brian Goetz 对“线程安全“有一个比较恰到的定义:“当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那这个对象就是线程安全的。” 看完这一段定义,我们可以理解为,当我们在编写代码的时候不需要考虑线程问题即不加上同步处理,程序的运行结果仍然会是正常的,那我们可以说这是线程安全的。比如上面这段代码,如果我们不加上synchronized关键字,那么在多线程环境下,很有可能会创建多个单例对象,很显然这不是我们想要的,也违背了单例模式的设计原则。
线程安全问题,说白了就是多个线程在操作共享数据时引发的数据安全问题。
在java语言中,使用synchronized关键字是我们使用互斥同步的方式(还有其他的方式保证线程安全,日后再聊)来保证线程安全的常用手段,那是不是只要涉及线程安全问题,我们都可以用synchronize来解决呢?使用synchronized关键字会不会对性能有什么影响?使用synchronized关键字的缺陷又在哪里呢?接下来我们就好好的聊一聊,synchronized关键字。
简单的示例代码:
public class SyncDemo { //修饰实例方法 public synchronized void syncMethod(){ //对象锁 } public void syncCode(){ //修饰代码块 synchronized (this){ // 括号表示作用范围 this是对象级别 SyncDemo.class类级别 //保护存在线程安全的变量 } } //修饰静态方法 public synchronized static void syncStaticMethod(){ //类锁 //TODO } }
以上代码表示synchronized关键字的两种作用范围,一种作用于对象,一种作用于类。观察synchronized 的整个语法发现,synchronized(lock)是基于lock 这个对象的生命周期来控制锁粒度的,如果这个对象是类,那么作用范围是类级别,如果是对象,那么作用范围就是对象。显而易见类级别的范围要大于对象级别(类的生命周期>对象的生命周期),锁的级别越小,对程序性能的影响也越小。
synchronized 关键字经过编译之后,会在同步块的前后分别形成monitorenter和monitorexit这两个字节码指令,这两个字节码都需要- 个reference类型的参数来指明要锁定和解锁的对象。如果Java程序中的synchronized明确指定了对象参数,那就是这个对象的reference ;如果没有明确指定,那就根据synchronized修饰的是实例方法还是类方法,去取对应的对象实例或Class对象来作为锁对象。
标签:共享数据 类锁 style 简单的 指令 关键字 exit 存在 额外
原文地址:https://www.cnblogs.com/chalice/p/11265421.html