分享

Java并发编程:synchronized

 月冷星河 2016-07-20

根据前面讲的Java内存模型,已经接触不少synchronized,而且它非常强大,能解决大部分的并发问题,今天我们一起来学习它吧。

以下是本文包含的知识点:

1.Java的线程安全

2.synchronized的用法

3.synchronized的实现原理

一、Java的线程安全

我们这里讨论的线程安全,限定于多个线程之间存在共享数据访问的这个前提下。如果一段代码根本不会和其它线程共享数据,那么也不存在线程安全的问题。

那我们应该如何实现线程安全呢?

互斥同步是一种常见的并发正确性保障手段,同步是指在多个线程并发访问共享数据时,保证共享数据在同一个时刻只被一个线程使用。而互斥是实现同步的一种手段。

在Java中最基本的互斥同步手段就是synchronized关键字。还有一种是重入锁(ReentrantLock),后面会讲到。

二、synchronized的用法

可以参考之前的文章Thread类的使用,线程同步一节有讲到

1.作用于代码块上,只同步这一段代码:

synchronize(this){//this指锁定当前对象 num++; System. out.println(name + ', 你是第' + num + '个使用timer的线程' );}

2.放在方法声明中,表明整个方法为同步方法:

public synchronized void add(String name) {//还可以修饰static方法 num++; System. out.println(name + ', 你是第' + num + '个使用timer的线程' );}

有几点需要注意的地方:

1.当一个线程正在访问一个对象的synchronized方法时,其它线程不能访问该对象的其它synchronized方法。因为该对象的锁还未被释放,其它线程拿不到。

2.当一个线程正在访问一个对象的synchronized方法时,其它线程可以访问该对象的其它非synchronized方法。因为非synchronized方法,不需要锁。

3.当一个线程正在访问一个对象的synchronized方法时,其它线程可以访问其它对象的synchronized方法或非synchronized方法。因为锁的对象不一样。

另外,每个类也有自己的锁,被synchronized修饰的static方法,类锁与对象的锁也不会发生互斥。看下面代码:

public synchronized void test1{//对象锁 //}public synchronized static void test2{//类锁 //}

当多线程同时访问test1和test2时,可以并发访问,不会发生互斥。因为锁的对象不一样,一个是类,一个是对象。

三、synchronized的实现原理

synchronized关键字经过编译后,会在同步块的前后分别形成monitorenter和monitorexit这两个字节码指令,这两个字节码都需要一个reference类型参数来指明需要锁定和解锁的对象。如果在程序中明确指定了对象参数,那就是这个对象的reference,如果没有明确指定,那根据synchronized修饰的是实例方法还是静态方法,去取对应的对象实例或Class对象来作为锁对象。

看下面这段代码:

package com.yuwl.thread.demo;public class TestSynchronized { public void test1{ } public void test2{ synchronized( this){ } } public synchronized void test3{ } }

对其反编译的字节码为:

Java并发编程:synchronized

从反编译的字节码可以看出,加了synchronized的代码块多了两个指令。

根据虚拟机规范的要求,在执行monitorenter指令时,首先要尝试获取对象的锁。如果已经拿到对象的锁,则把计数器加1,相应的在执行monitorexit指令时会将计数器减1,当计算器为0时,锁就被释放了。如果获取对象失败,那当前线程就要阻塞等待,直到对象锁被另外一个线程释放。对于synchronized方法,执行中的线程会识别该方法的method_info结构是否有ACC_SYNCHRONIZED标记,如果有会自动获取对象的锁,调用方法,最后释放锁。

synchronized还有一个重要特性——可重入性,不会自己把自己锁死。解释下,比喻一个线程执行同步方法1,而同步方法1又要调用同步方法2,这种情况是可重入的。

synchronized对异常的处理,如果同步块有异常发生,线程会自动释放锁。

参考

《深入Java 虚拟机》

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多