JAVA中synchronized关键字能够作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句块。搞清楚synchronized锁定的是哪个对象,就能帮助我们设计更安全的多线程程式。

不久前用到了同步,现在回过头来对JAVA中的同步做个总结,以对前段时间工作的总结和自我技术的条理话。JAVA的synchronized关键字能够作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句块。假如再细的分类,synchronized可作用于instance变量、object reference(对象引用)、static函数和class literals(类名称字面常量)身上。
在进一步阐述之前,我们需要明确几点:
A.无论synchronized关键字加在方法上还是对象上,他取得的锁都是对象,而不是把一段代码或函数当作锁――而且同步方法很可能还会被其他线程的对象访问。
B.每个对象只有一个锁(lock)和之相关联。
C.实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。
接着来讨论synchronized用到不同地方对代码产生的影响:

假设P1、P2是同一个类的不同对象,这个类中定义了以下几种情况的同步块或同步方法,P1、P2就都能够调用他们。

Java的synchronized使用方法总结

1. 把synchronized当作函数修饰符时,示例代码如下:

Public synchronized void method(){
//….
}
这也就是同步方法,那这时synchronized锁定的是哪个对象呢?他锁定的是调用这个同步方法对象。也就是说,当一个对象P1在不同的线程中执行这个同步方法时,他们之间会形成互斥,达到同步的效果。但是这个对象所属的Class所产生的另一对象P2却能够任意调用这个被加了synchronized关键字的方法。
上边的示例代码等同于如下代码:

public void method()
{
synchronized (this) // (1)
{
//…..
}
}
(1)处的this指的是什么呢?他指的就是调用这个方法的对象,如P1。可见同步方法实质是将synchronized作用于object reference。――那个拿到了P1对象锁的线程,才能够调用P1的同步方法,而对P2而言,P1这个锁和他毫不相干,程式也可能在这种情形下摆脱同步机制的控制,造成数据混乱。

2.同步块,示例代码如下:

public void method(SomeObject so) {
synchronized(so)
{
//…..
}
}
这时,锁就是so这个对象,谁拿到这个锁谁就能够运行他所控制的那段代码。当有一个明确的对象作为锁时,就能够这样写程式,但当没有明确的对象作为锁,只是想让一段代码同步时,能够创建一个特别的instance变量(他得是个对象)来充当锁:

class Foo implements Runnable
{
private byte[] lock = new byte[0]; // 特别的instance变量
Public void method()
{
synchronized(lock) { //… }
}
//…..
}
注:零长度的byte数组对象创建起来将比任何对象都经济――查看编译后的字节码:生成零长度的byte[]对象只需3条操作码,而Object lock = new Object()则需要7行操作码。

3.将synchronized作用于static 函数,示例代码如下:

Class Foo
{
public synchronized static void method1() // 同步的static 函数
{
//….
}
public void method2()
{
synchronized(Foo.class) // class literal(类名称字面常量)
}
}

代码中的method2()方法是把class literal作为锁的情况,他和同步的static函数产生的效果是相同的,取得的锁很特别,是当前调用这个方法的对象所属的类(Class,而不再是由这个Class产生的某个具体对象了)。
记得在《Effective Java》一书中看到过将 Foo.class和 P1.getClass()用于作同步锁还不相同,不能用P1.getClass()来达到锁这个Class的目的。P1指的是由Foo类产生的对象。
能够推断:假如一个类中定义了一个synchronized的static函数A,也定义了一个synchronized 的instance函数B,那么这个类的同一对象Obj在多线程中分别访问A和B两个方法时,不会构成同步,因为他们的锁都不相同。A方法的锁是Obj所属的那个Class,而B的锁是Obj所属的这个对象。

Java的synchronized使用方法小结如下:

搞清楚synchronized锁定的是哪个对象,就能帮助我们设计更安全的多线程程式。

更有一些技巧能够让我们对共享资源的同步访问更加安全:
1. 定义private 的instance变量+他的 get方法,而不要定义public/protected的instance变量。假如将变量定义为public,对象在外界能够绕过同步方法的控制而直接取得他,并改变他。这也是JavaBean的标准实现方式之一。
2. 假如instance变量是个对象,如数组或ArrayList什么的,那上述方法仍然不安全,因为当外界对象通过get方法拿到这个instance对象的引用后,又将其指向另一个对象,那么这个private变量也就变了,岂不是很危险。 这个时候就需要将get方法也加上synchronized同步,并且,只返回这个private对象的clone()――这样,调用端得到的就是对象副本的引用了。

本文来自leo_faith的博客。

 

Java的synchronized关键字:同步机制总结的更多相关文章

  1. Java 多线程 —— synchronized关键字

    java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...

  2. java基础Synchronized关键字之对象锁

    java中Synchronized关键字之对象锁    当有多个线程对一个共享数据进行操作时,需要注意多线程的安全问题. 多线程的同步机制对资源进行加锁,使得在同一个时间,只有一个线程可以进行操作,同 ...

  3. Java基础-synchronized关键字的用法(转载)

    synchronized--同步 顾名思义是用于同步互斥的作用的. 这里精简的记一下它的使用方法以及意义: 当synchronized修饰 this或者非静态方法或者是一个实例的时候,所同步的锁是加在 ...

  4. 从分布式锁角度理解Java的synchronized关键字

    分布式锁 分布式锁就以zookeeper为例,zookeeper是一个分布式系统的协调器,我们将其理解为一个文件系统,可以在zookeeper服务器中创建或删除文件夹或文件.设D为一个数据系统,不具备 ...

  5. java中synchronized关键字分析

    今天我们来分析一下java中synchronized关键字.首先来看一段java代码:(本地编译环境为mac,jdk1.8的环境) Demo.java package com.example.spri ...

  6. java并发:线程同步机制之Volatile关键字&原子操作Atomic

    volatile关键字 volatile是一个特殊的修饰符,只有成员变量才能使用它,与Synchronized及ReentrantLock等提供的互斥相比,Synchronized保证了Synchro ...

  7. JAVA synchronized关键字锁机制(中)

    synchronized 锁机制简单的用法,高效的执行效率使成为解决线程安全的首选. 下面总结其特性以及使用技巧,加深对其理解. 特性: 1. Java语言的关键字,当它用来修饰一个方法或者一个代码块 ...

  8. Java多线程初学者指南(10):使用Synchronized关键字同步类方法

    要想解决“脏数据”的问题,最简单的方法就是使用synchronized关键字来使run方法同步,代码如下: public synchronized void run() { ... } 从上面的代码可 ...

  9. java synchronized 线程同步机制详解

    Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码. 一.当两个并发线程访问同一个对象object中的这个synchronized(this ...

随机推荐

  1. defrag磁盘整理命令

    1: Microsoft 磁盘碎片整理程序 2: 版权所有 (c) 2007 Microsoft Corp. 3: 参数错误. (0x80070057) 4: 描述: 5: 定位并合并本地卷中的碎片文 ...

  2. 利用Nutch和Tomcat构建搜索引擎

    利用Nutch和Tomcat构建搜索引擎 1.安装环境及软件版本介绍 本教程是在Linux Ubuntu 12.04 desktop i386操作系统上搭建,结合使用了Nutch-1.2和Apache ...

  3. 卡通投掷游戏ios源码

    卡通投掷游戏源码,一款基于cocos2d很有意思的卡通投掷游戏源码,使用重力感应摇动手机让猴子打转,然后点击屏幕任何地方将猴子抛出去,抛出去的过程中会收集星星,游戏的规则就是抛得越远越好,收集的星星最 ...

  4. Windows Phone 8.1开发:如何让ListView下拉加载更多?

    Windows Phone 8.1开发中使用ListView作为数据呈现载体时,经常需要一个下拉(拇指向上滑动)加载更多的交互操作.如何完成这一操作呢?下面为您阐述. 思路是这样的: 1.在ListV ...

  5. linux 编译内核[scripts/kconfig/dochecklxdialog] 错误

    administrator@ubuntu:~/linux-2.6.28-omap$ make menuconfig *** Unable to find the ncurses libraries o ...

  6. IntelliJ IDEA+Tomcat+Nginx运行git项目

    1.克隆Git项目到本地 (1)设置Git工具路径:file>settings>Version Control>Git (2)设置GitHub账户:file>settings& ...

  7. 将json转为复杂url参数

    //json转url参数 var parseParam = function(param, key) { var paramStr = ""; if (param instance ...

  8. 【Qt】Qt国际化(系统文本-QMessageBox按钮、QLineEdit右键菜单等)【转】

    简介 使用Qt的时候,经常会遇到英文问题,例如:QMessageBox中的按钮.QLineEdit.QSpinBox.QScrollBar中的右键菜单等.通常情况下,我们软件都不会是纯英文的,那么如何 ...

  9. 关于promise对象的笔记

    1.promise对象是ECMAScript6的新特性,很多新的JS框架都有它的实现和应用 2.promise常用于异步调用(ajax)中 3.promise主要用于解决回调函数层层嵌套的写法 4.要 ...

  10. Swift初步介绍

    Swift是本届WWDC大会苹果推出的一门新开发语言,开发者网站上已经放出了这门新语言的介绍.教程和手册,如果手里有一台iOS设备的话,通过苹果的iBooks应用,从它的官方书店里搜索Swift,可以 ...