java synchronized支持

1.什么是同步,为什么要使用同步
为什么会需要同步,这里不得不提到多线程,同步主要是应对多线程的数据访问出现的技术。
多线程的作用大家应该已经很清楚,提高资源利用率,提升性能。
先看一下同步定义:是一种防止对共享资源访问导致的数据不一致的一种模式。
我们以一段多线程的程序和JVM的内存模型知识来说明下多线程情况下不采用同步技术数据出现不一致的情况:

private static Integer i = new Integer(0);


public static void main(String[] args) {
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
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值