- java代码在编译后会变成java的字节码,字节码会被类加载器加载到jvm里,jvm执行字节码,最终转化为汇编指令在cpu上运行,这个过程是java代码执行的基本原理,编程的最终还是与cpu和内存的交互,多线程编程带来的挑战之一便是如何能让多个线程同时执行一个任务的时候不出错? 具体到同时修改一个变量的时候如何不出错? java底层基本是通过“锁”的概念来做。
- java中有两个常见的锁,volatile和synchronized
volatile关键字原理
- volatile关键字的定义是:java编程语言允许线程访问共享变量,为了保证共享变量能被准确和一致的更新,线程应该确保通过排他锁获取这个变量。
- 通过定义我们可以知道这个关键字的几个特点: 1,修饰的是共享的变量【不能修饰方法和类】 2,只保证可见性,不保证一致性。 3,为了保证一致性,修改的时候必须添加排它锁。
- volatile的有两条实现的原则: 1,lock前缀指令会引发处理器缓存写回到内存 2,第一步操作会使得其他处理器的该变量的缓存失效。
-
lock前缀指令会引发处理器缓存写回到内存
当处理器修改volatile修饰的变量的时候,会引起处理器的缓存写回到主内存,但是一般不会锁定整个总线,而是锁定缓存。 -
第一步操作会使得其他处理器的该变量的缓存失效
处理器会有嗅探技术对volatile修饰的变量进行监控,如果有写会的操作,缓存失效,则会通知定义嗅探的线程。原理类似于监听。 - volatile的使用优化:
- 有一种优化的方式,是为缓存行追加字节,使得其变为64字节这种优化的方式是有些处理器的高速缓存行的字节数为64字节宽,如果没有追加的话,多个缓存行可能会被放入同一个高速缓存行,当有写操作的时候,整个行被锁定。 有两种情况下可以不追加 1,处理器的高速缓存行不是64, 2 共享变量不会频繁的写导致缓存锁定。
synchronized关键字原理
- java存在并发编程之初,synchronized就一直存在,可谓是元老级的锁,很多人称之为重量级锁,随1.6的各种优化,synchronized并没有那么重了, 1.6为了减少获取锁和释放锁带来的性能消耗引入了偏向锁和轻量级的锁。
- synchronized可以修饰变量,方法,类。
- synchronized修饰普通的方法: 锁定当前的实例对象。
- synchronized修饰静态方法: 锁定当前类的class对象。
- synchronized修饰同步方法块:锁定方法块里的配置的对象。
- synchronized在jvm的实现原理基于进入和退出Monitor对象来实现方法和方法块的同步。
【偏向锁】: 简单的来说就是一个锁对线程有偏向的意思,在java中锁一共有四种状态,由高到低依次为无状态锁,偏向锁,轻量级锁,重量级锁。