synchronized关键字有两种用法。第一种就是在《使用Synchronized关键字同步类方法》一文中所介绍的直接用在方法的定义中。另外一种就是synchronized块。我们不仅可以通过synchronized块来同步一个对象变量。也可以使用synchronized块来同步类中的静态方法和非静态方法。

synchronized块的语法如下:


public void method() { … … synchronized(表达式) { … … } }

一、非静态类方法的同步

从《使用Synchronized关键字同步类方法》一文中我们知道使用synchronized关键字来定义方法就会锁定类中所有使用synchronzied关键字定义的静态方法或非静态方法,但这并不好理解。而如果使用synchronized块来达到同样的效果,就不难理解为什么会产生这种效果了。如果想使用synchronized块来锁定类中所有的同步非静态方法,需要使用this做为synchronized块的参数传入synchronized块国,代码如下:

通过synchronized块同步非静态方法


public class SyncBlock { public void method1() { synchronized(this) // 相当于对method1方法使用synchronized关键字 { … … } } public void method2() { synchronized(this) // 相当于对method2方法使用synchronized关键字 { … … } } public synchronized void method3() { … … } }

在上面的代码中的method1和method2方法中使用了synchronized块。而第017行的method3方法仍然使用synchronized关键字来定义方法。在使用同一个SyncBlock类实例时,这三个方法只要有一个正在执行,其他两个方法就会因未获得同步锁而被阻塞。在使用synchronized块时要想达到和synchronized关键字同样的效果,必须将所有的代码都写在synchronized块中,否则,将无法使当前方法中的所有代码和其他的方法同步。

除了使用this做为synchronized块的参数外,还可以使用SyncBlock.this作为synchronized块的参数来达到同样的效果。

在内部类(InnerClass)的方法中使用synchronized块来时,this只表示内类,和外类(OuterClass)没有关系。但内类的非静态方法可以和外类的非静态方法同步。如在内类InnerClass中加一个method4方法,并使method4方法和SyncBlock的三个方法同步,代码如下:

使内类的非静态方法和外类的非静态方法同步


public class SyncBlock { … … class InnerClass { public void method4() { synchronized(SyncBlock.this) { … … } } } … … }

在上面SyncBlock类的新版本中,InnerClass类的method4方法和SyncBlock类的其他三个方法同步,因此,method1、method2、method3和method4四个方法在同一时间只能有一个方法执行。

Synchronized块不管是正常执行完,还是因为程序出错而异常退出synchronized块,当前的synchronized块所持有的同步锁都会自动释放。

因此,在使用synchronized块时不必担心同步锁的释放问题。

二、静态类方法的同步

由于在调用静态方法时,对象实例不一定被创建。因此,就不能使用this来同步静态方法,而必须使用Class对象来同步静态方法。代码如下:

通过synchronized块同步静态方法


public class StaticSyncBlock { public static void method1() { synchronized(StaticSyncBlock.class) { … … } } public static synchronized void method2() { … … } }

在同步静态方法时可以使用类的静态字段class来得到Class对象。在上例中method1和method2方法同时只能有一个方法执行。除了使用class字段得到Class对象外,还可以使用实例的getClass方法来得到Class对象。上例中的代码可以修改如下:

使用getClass方法得到Class对象


public class StaticSyncBlock { public static StaticSyncBlock instance; public StaticSyncBlock() { instance = this; } public static void method1() { synchronized(instance.getClass()) { } } }

在上面代码中通过一个public的静态instance得到一个StaticSyncBlock类的实例,并通过这个实例的getClass方法得到了Class对象(一个类的所有实例通过getClass方法得到的都是同一个Class对象,因此,调用任何一个实例的getClass方法都可以)。我们还可以通过Class对象使不同类的静态方法同步,如Test类的静态方法method和StaticSyncBlock类的两个静态方法同步,代码如下:

Test类的method方法和StaticSyncBlock类的method1、method2方法同步


public class Test { public static void method() { synchronized(StaticSyncBlock.class) { } } }

注意:在使用synchronized块同步类方法时,非静态方法可以使用this来同步,而静态方法必须使用Class对象来同步。它们互不影响。当然,也可以在非静态方法中使用Class对象来同步静态方法。但在静态方法中不能使用this来同步非静态方法。这一点在使用synchronized块同步类方法时应注意。

使用Synchronized块同步方法的更多相关文章

  1. Java多线程初学者指南(11):使用Synchronized块同步方法

    synchronized关键字有两种用法.第一种就是在<使用Synchronized关键字同步类方法>一文中所介绍的直接用在方法的定义中.另外一种就是synchronized块.我们不仅可 ...

  2. java synchronized静态同步方法与非静态同步方法,同步语句块

    摘自:http://topmanopensource.iteye.com/blog/1738178 进行多线程编程,同步控制是非常重要的,而同步控制就涉及到了锁. 对代码进行同步控制我们可以选择同步方 ...

  3. Java多线程初学者指南(12):使用Synchronized块同步变量

    我们可以通过synchronized块来同步特定的静态或非静态方法.要想实现这种需求必须为这些特性的方法定义一个类变量,然后将这些方法的代码用synchronized块括起来,并将这个类变量作为参数传 ...

  4. 使用Synchronized块同步变量

    我们可以通过synchronized块来同步特定的静态或非静态方法.要想实现这种需求必须为这些特定的方法定义一个类变量,然后将这些方法的代码用synchronized块括起来,并将这个类变量作为参数传 ...

  5. Synchronized块同步变量的误区

    我们可以通过synchronized块来同步特定的静态或非静态方法.要想实现这种需求必须为这些特性的方法定义一个类变量,然后将这些方法的代码用synchronized块括起来,并将这个类变量作为参数传 ...

  6. 用生活例子来解释Java synchronized块

    今天满世界的微信小程序的新闻,大家都说对于Android原生程序有构成危险了,我也不想了,以后的事谁知道呢, 我还是好好执行一下今年的计划吧.  项目刚刚上线,最近没啥事,我一直感觉自己的Java基础 ...

  7. synchronized块中的wait()、nofity()、nofityAll()方法

    前言 在Java并发编程实战,会经常遇到多个线程访问同一个资源的情况,这个时候就需要维护数据的一致性,否则会出现各种数据错误,其中一种同步方式就是利用Synchronized关键字执行锁机制,锁机制是 ...

  8. 线程同步 synchronized 同步代码块 同步方法 同步锁

    一 同步代码块 1.为了解决并发操作可能造成的异常,java的多线程支持引入了同步监视器来解决这个问题,使用同步监视器的通用方法就是同步代码块.其语法如下: synchronized(obj){ // ...

  9. 线程的同步机制:同步代码块&同步方法

    解决存在的线程安全问题:打印车票时出现重票,错票 使用同步代码块的解决方案 TestWindow2 package com.aff.thread; /* 使用实现Runnable接口的方式,售票 存在 ...

随机推荐

  1. python urllib和urllib3包使用(转载于)

    urllib.request 1. 快速请求 2.模拟PC浏览器和手机浏览器 3.Cookie的使用 4.设置代理 urllib.error URLError HTTPError urllib.par ...

  2. webpack进阶--打包

    上一片博文主要让大家了解下究竟webpack是干什么的,明显它是专注于打包的. gulp  和  webpack  的区别 gulp,要求我们一步步写task(es6编译.css压缩.图片压缩.打包. ...

  3. ASP.NET记录错误日志的方式

    程序记录错误日志是一种看起来对一般用户没什么作用,但对程序开发者用处很大的东西,它能查出错误或异常的程序马迹.那么,常用的记录错误日志的方式有哪些呢? 大多数情况下使用的是 1.直接记录为txt/xm ...

  4. Java 多线程(Thread) 同步(synchronized) 以及 wait, notify 相关 [实例介绍]

    场景描述 有一家很大的商场,在某市有几个商品配送中心,并有几家分店,这家商场经营很多的商品,平时运营情况是这样的: 根据各分店的商品销售情况,给分店配送相应需求量的商品:并上架到分店指让的位置,供客户 ...

  5. CS229 笔记06

    CS229 笔记06 朴素贝叶斯 事件模型 事件模型与普通的朴素贝叶斯算法不同的是,在事件模型中,假设文本词典一共有 \(k\) 个词,训练集一共有 \(m\) 封邮件,第 \(i\) 封邮件的词的个 ...

  6. MAC Book 共享网络连接

    CHENYILONG Blog MAC Book 共享网络连接 MAC Book 共享网络连接 MAC比Windows共享连接要方便很多,只需要以下两步操作: 1.打开系统偏好设置,选择共享 2.选择 ...

  7. 【源码阅读】VS调试mimikatz-改造法国神器mimikatz执行就获取明文密码

    0x1 概要 记得某位同学提起在XXX得到了一个一键生成明文的工具,觉得很是神奇... 然而我一看图标就知道是mimikatz,这工具是开源的,只要改两行代码就可以实现写死命令了. 顺带讲讲编译过程中 ...

  8. IE浏览器如何调试Asp.net的 js代码

    不管我们开发什么项目,都需要使用调试.后端的调试比较简单.前端js调试稍微复杂了一点,但是也别怕,因为我们有很多调试前端js代码的浏览器工具.比如IE浏览器.firefox浏览器.chrome浏览器等 ...

  9. SSL邮件发送(腾讯企业邮箱测试通过,可以支持多附件)

    参考网址:http://www.cnblogs.com/LUA123/p/5575134.html ,谢谢! package net.common.utils.common; import java. ...

  10. WCF开发中将net.tcp协议寄宿到IIS的方法

    1 部署IIS 1.1 安装WAS IIS原本是不支持非HTTP协议的服务,为了让IIS支持net.tcp,必须先安装WAS(Windows Process Activation Service),即 ...