文章转Hollis博客 大家可以关注下,很多技术类型的文章
在再有人问你Java内存模型是什么,就把这篇文章发给他。中我们曾经介绍过,Java语言为了解决并发编程中存在的原子性、可见性和有序性问题,提供了一系列和并发处理相关的关键字,比如synchronized
、volatile
、final
、concurren包
等。
在《深入理解Java虚拟机》中,有这样一段话:
synchronized
关键字在需要原子性、可见性和有序性这三种特性的时候都可以作为其中一种解决方案,看起来是“万能”的。的确,大部分并发控制操作都能使用synchronized来完成。
海明威在他的《午后之死》说过的:“冰山运动之雄伟壮观,是因为他只有八分之一在水面上。”对于程序员来说,synchronized
只是个关键字而已,用起来很简单。之所以我们可以在处理多线程问题时可以不用考虑太多,就是因为这个关键字帮我们屏蔽了很多细节。
那么,本文就围绕synchronized
展开,主要介绍synchronized
的用法、synchronized
的原理,以及synchronized
是如何提供原子性、可见性和有序性保障的等。
synchronized的用法
synchronized
是Java提供的一个并发控制的关键字。主要有两种用法,分别是同步方法和同步代码块。也就是说,synchronized
既可以修饰方法也可以修饰代码块。
/**
* @author Hollis 18/08/04.
*/
public class SynchronizedDemo { //同步方法 public synchronized void doSth(){ System.out.println("Hello World"); } //同步代码块 public void doSth1(){ synchronized (SynchronizedDemo.class){ System.out.println("Hello World"); } } }
被synchronized
修饰的代码块及方法,在同一时间,只能被单个线程访问。
synchronized的实现原理
synchronized
,是Java中用于解决并发情况下数据同步访问的一个很重要的关键字。当我们想要保证一个共享资源在同一时间只会被一个线程访问到时,我们可以在代码中使用synchronized
关键字对类或者对象加锁。
在深入理解多线程(一)——Synchronized的实现原理中我曾经介绍过其实现原理,为了保证知识的完整性,这里再简单介绍一下,详细的内容请去原文阅读。
我们对上面的代码进行反编译,可以得到如下代码:
public synchronized void doSth(); descriptor: ()V flags: ACC_PUBLIC, ACC_SYNCHRONIZED Code: stack=2, locals=1, args_size=1 0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3 // String Hello World 5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: return public void doSth1(); descriptor: ()V flags: ACC_PUBLIC Code: stack=2, locals=3, args_size=1 0: ldc #5 // class com/hollis/SynchronizedTest 2: dup 3: astore_1 4: monitorenter 5: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 8: ldc #3 // String Hello World 10: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 13: aload_1 14: monitorexit 15: goto 23 18: astore_2 19