java synchronized支持
来源:互联网 发布:mac口红brave red试色 编辑:程序博客网 时间:2024/05/29 10:43
1.什么是同步,为什么要使用同步
为什么会需要同步,这里不得不提到多线程,同步主要是应对多线程的数据访问出现的技术。
多线程的作用大家应该已经很清楚,提高资源利用率,提升性能。
先看一下同步定义:是一种防止对共享资源访问导致的数据不一致的一种模式。
我们以一段多线程的程序和JVM的内存模型知识来说明下多线程情况下不采用同步技术数据出现不一致的情况:
Thread athread = new Thread(new Runnable() {
public void run() {
for (int ind = 0; ind < 10000; ind++) {
i++;
}
}
});
Thread bthread = new Thread(new Runnable() {
public void run() {
for (int ind = 0; ind < 10000; ind++) {
i++;
}
}
});
athread.start();
bthread.start();
try {
athread.join();
bthread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i);
}
结果大部分情况都不是20000
java的内存模型是每一个进程都有一个主内存,每个线程都拥有私有的内存,线程可以从主内存获取数据和进行相关操作,操作完成后可以结果重新存入主内存。
如下图显示:
而上述代码的运行情况,会导致线程t1/t2操作的数据覆盖线程t2/t1存入主内存中结果,这样i总是会缺斤少两,最后的运行结果并不是预想的值20000。
下图举例说明一种可能覆盖的情况:
同步就是为了解决这种数据不一致的而存在的。
2.JVM是如何支持同步的
以下是JVM规范:
JVM通过一个单一的同步结构(监视器)来支持同步,支持同步的两种方式:方法指令和在方法中的指令序列。
2.1方法指令(隐式同步)
方法级别的同步是作为方法调用、返回指令的一部分隐式执行的。一个同步方法是通过运行期常量池中的ACC_SYNCHRONIZED标志来区分,ACC_SYNCHRONIZED这个常量会被方法调用指令检测。当调用一个设置了ACC_SYNCHRONIZED 标志的方法(同步方法)时,正在执行的线程进入监视器,调用线程自身的方法;当方法正常执行完毕或者异常时退出监视器。假如正在执行的线程拥有监视器时,其他的线程不能进入监视器。当调用的同步方法正在执行时抛出异常并且异常没有被同步方法所捕获时,在异常被同步方法重新重新抛出之前同步方法所拥有的监视器自动退出。
注:方法级别隐式同步是相对于JVM来说的。
2.2指令序列(显式同步)
在java语言中,用来编写同步代码块的典型是同步序列指令。JVM提供了monitorenter和monitorexit指令来支持这种同步结构。正确的实现同步块需要和支持JVM的编译器配合。
结构化锁定:当方法调用时,监视器的每一个退出之前匹配一个进入。由于并没有保证所有提交至JVM的代码全部执行结构化锁,JVM的实现允许但是并不强制执行以下两个规则以保证结构化锁。
假设T是一个线程,M是一个监视器。这两个规则如下:
*在M上的T执行一个方法期间,不管方法正常运行完毕还是发生异常,线程上的进入监视器的次数必须与退出监视器的次数相等。
注:一个线程可以拥有很多个监视器
*在M上的T执行一个方法期间,不允许线程执行退出监视器的次数超进入监视器的次数。
需要注意的是当JVM调用同步方式时,监视器进入和退出由JVM自动执行。进入退出监视器的操作被认为发生在方法调用期间。
3.java语言中使用同步(隐式和显式)
java语言中使用同步都是通过使用synchronized关键字。
//隐式同步
public synchronized void testA(){
System.out.println("testA");
}
//显式同步
public void testB(){
synchronized(this){
System.out.println("testB");
}
}
可以使用java自带的javap命令看一下字节码,关键部分如下:
public synchronized void testA();
flags: ACC_PUBLIC, ACC_SYNCHRONIZED
Code:
stack=2, locals=1, args_size=1
...
8:return
public void testB();
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=1
...
3: monitorenter
...
13: monitorexit
20: return
java语言中的synchronized方法和synchronized块就是用来获取监视器的两种方法,获取监视器线程才能执行,进而达到对同步的支持。
为什么会需要同步,这里不得不提到多线程,同步主要是应对多线程的数据访问出现的技术。
多线程的作用大家应该已经很清楚,提高资源利用率,提升性能。
先看一下同步定义:是一种防止对共享资源访问导致的数据不一致的一种模式。
我们以一段多线程的程序和JVM的内存模型知识来说明下多线程情况下不采用同步技术数据出现不一致的情况:
private static Integer i = new Integer(0);
Thread athread = new Thread(new Runnable() {
public void run() {
for (int ind = 0; ind < 10000; ind++) {
i++;
}
}
});
Thread bthread = new Thread(new Runnable() {
public void run() {
for (int ind = 0; ind < 10000; ind++) {
i++;
}
}
});
athread.start();
bthread.start();
try {
athread.join();
bthread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i);
}
结果大部分情况都不是20000
java的内存模型是每一个进程都有一个主内存,每个线程都拥有私有的内存,线程可以从主内存获取数据和进行相关操作,操作完成后可以结果重新存入主内存。
如下图显示:
而上述代码的运行情况,会导致线程t1/t2操作的数据覆盖线程t2/t1存入主内存中结果,这样i总是会缺斤少两,最后的运行结果并不是预想的值20000。
下图举例说明一种可能覆盖的情况:
同步就是为了解决这种数据不一致的而存在的。
2.JVM是如何支持同步的
以下是JVM规范:
JVM通过一个单一的同步结构(监视器)来支持同步,支持同步的两种方式:方法指令和在方法中的指令序列。
2.1方法指令(隐式同步)
方法级别的同步是作为方法调用、返回指令的一部分隐式执行的。一个同步方法是通过运行期常量池中的ACC_SYNCHRONIZED标志来区分,ACC_SYNCHRONIZED这个常量会被方法调用指令检测。当调用一个设置了ACC_SYNCHRONIZED 标志的方法(同步方法)时,正在执行的线程进入监视器,调用线程自身的方法;当方法正常执行完毕或者异常时退出监视器。假如正在执行的线程拥有监视器时,其他的线程不能进入监视器。当调用的同步方法正在执行时抛出异常并且异常没有被同步方法所捕获时,在异常被同步方法重新重新抛出之前同步方法所拥有的监视器自动退出。
注:方法级别隐式同步是相对于JVM来说的。
2.2指令序列(显式同步)
在java语言中,用来编写同步代码块的典型是同步序列指令。JVM提供了monitorenter和monitorexit指令来支持这种同步结构。正确的实现同步块需要和支持JVM的编译器配合。
结构化锁定:当方法调用时,监视器的每一个退出之前匹配一个进入。由于并没有保证所有提交至JVM的代码全部执行结构化锁,JVM的实现允许但是并不强制执行以下两个规则以保证结构化锁。
假设T是一个线程,M是一个监视器。这两个规则如下:
*在M上的T执行一个方法期间,不管方法正常运行完毕还是发生异常,线程上的进入监视器的次数必须与退出监视器的次数相等。
注:一个线程可以拥有很多个监视器
*在M上的T执行一个方法期间,不允许线程执行退出监视器的次数超进入监视器的次数。
需要注意的是当JVM调用同步方式时,监视器进入和退出由JVM自动执行。进入退出监视器的操作被认为发生在方法调用期间。
3.java语言中使用同步(隐式和显式)
java语言中使用同步都是通过使用synchronized关键字。
//隐式同步
public synchronized void testA(){
System.out.println("testA");
}
//显式同步
public void testB(){
synchronized(this){
System.out.println("testB");
}
}
可以使用java自带的javap命令看一下字节码,关键部分如下:
public synchronized void testA();
flags: ACC_PUBLIC, ACC_SYNCHRONIZED
Code:
stack=2, locals=1, args_size=1
...
8:return
public void testB();
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=1
...
3: monitorenter
...
13: monitorexit
20: return
java语言中的synchronized方法和synchronized块就是用来获取监视器的两种方法,获取监视器线程才能执行,进而达到对同步的支持。
0 0
- java synchronized支持
- Java synchronized
- Java synchronized
- java synchronized
- java synchronized
- java synchronized
- java synchronized
- Java synchronized
- java synchronized
- java synchronized
- java synchronized
- java synchronized
- java synchronized
- java synchronized
- java synchronized
- java synchronized
- Java synchronized
- Java synchronized
- java.lang.OutOfMemoryError处理错误
- ArcFour加密解密,java RC4加密解密,java 加密解密
- hibernate多表关联配置
- c写的一个简单的计算器
- sun.misc.BASE64Encoder 和 sun.misc.BASE64Decoder包
- java synchronized支持
- HDU 3687 暴力
- Subsets II
- Opencv字体操作和设置
- 如何一个android工程作为另外一个android工程的lib
- 谈谈我所知道的API写法
- 修改tabhost的字体样式(颜色、字体大小) (有个R.id.title的问题)
- UIAlertController使用
- JAVA之代码混淆proguard基础(二)