多线程操作同一个对象时,容易引发线程安全问题。为了解决线程安全问题,Java多线程引入了同步监视器。

同步代码块

同步代码块语法格式如下:

synchronized(obj){
//此处的代码即为同步代码块
}

上面语法格式中synchronized后面括号的obj就是同步监视器,上面代码的含义是:线程开始执行同步代码块之前,必须先获得对同步监视器的锁定。

任何时刻只能有一条线程可以获得对同步监视器的锁定,当同步代码块执行结束后,该线程自然放弃了对同步监视器的锁定。

通常推荐使用可能被并发访问的共享资源当作同步监视器。

同步方法

同步方法就是用synchronized关键字来修饰某个方法,则该方法称为同步方法。对于同步方法而言,无需显式指定同步监视器,同步方法的同步监视器是this,即当前对象本身。

需要注意的是,synchronized关键字可以修饰代码块,可以修饰方法,但是不能修饰构造器、属性等。

可变类的线程安全是以降低程序运行效率为代价的,为减少线程安全所带来的负面影响,可以使用如下策略:

  • 不要对线程安全类的所有方法都进行同步,只对那些会改变共享资源的方法进行同步;
  • 为可变类提供两种版本:线程安全版本和线程不安全版本,以适应不同的运行环境。

释放同步监视器的锁定

线程进入同步方法或同步代码块后无法主动释放对同步监视器的锁定,线程会在如下几种情况下释放对同步监视器的锁定:

  • 同步方法、同步代码块执行结束;
  • 在执行同步方法、同步代码块时遇到break、return终止了同步代码块、同步方法的执行;
  • 在执行同步方法、同步代码块是遇到了Error或Exception,发生了中断;
  • 在执行同步方法、同步代码块时,执行了同步监视器对象的wait()方法,则当前线程暂停、并释放同步监视器。

在下面的情况下,程序不会释放同步监视器的锁定:

  • 在执行同步方法、同步代码块时,程序调用了Thread.sleep()、Thread.yield()来暂停当前线程的执行;
  • 在执行同步方法、同步代码块时,其他线程调用了当前线程的suspend方法将该线程挂起。

同步锁

同步锁通过显示定义同步锁对象来实现线程同步。这里同步锁使用Lock对象充当。

通常认为,同步锁提供了比同步代码块和同步方法更广泛的锁定操作。

synchronized 方法或语句的使用提供了对与每个对象相关的隐式监视器锁的访问,但却强制所有锁获取和释放均要出现在一个块结构中:当获取了多个锁时,它们必须以相反的顺序释放,且必须在与所有锁被获取时相同的词法范围内释放所有锁。

虽然 synchronized 方法和语句的范围机制使得使用监视器锁编程方便了很多,而且还帮助避免了很多涉及到锁的常见编程错误,但有时也需要以更为灵活的方式使用锁。例如,某些遍历并发访问的数据结果的算法要求使用 "hand-over-hand" 或 "chain locking":获取节点 A 的锁,然后再获取节点 B 的锁,然后释放 A 并获取 C,然后释放 B 并获取 D,依此类推。Lock 接口的实现允许锁在不同的作用范围内获取和释放,并允许以任何顺序获取和释放多个锁,从而支持使用这种技术。

Lock 实现提供了使用 同步方法和同步代码块所没有的其他功能,包括提供了一个非块结构的获取锁尝试 (tryLock())、一个获取可中断锁的尝试 (lockInterruptibly()) 和一个获取超时失效锁的尝试(tryLock(long, TimeUnit))。

Lock类还可以提供与隐式监视器锁完全不同的行为和语义,如保证排序、非重入用法或死锁检测。

Lock的实现类比较常用的是ReentrantLock。ReentrantLock锁具有同重入性,也就是说线程可以对它已经加锁的ReentrantLock锁再次加锁。

还有一个接口ReadWriteLock。ReadWriteLock 维护了一对相关的锁,一个用于只读操作,另一个用于写入操作。只要没有 writer,读取锁可以由多个 reader 线程同时保持。写入锁是独占的。 所有 ReadWriteLock 实现都必须保证 writeLock 操作的内存同步效果也要保持与相关 readLock 的联系。也就是说,成功获取读锁的线程会看到写入锁之前版本所做的所有更新。

死锁

当两个线程互相等待对方释放同步监视器就会发生死锁。Java虚拟机没有监测,也没有采用措施来处理死锁的情况。

预防死锁,需要防止线程在等待的情况占用资源。

Java多线程 - 线程同步的更多相关文章

  1. Java多线程——线程同步

    在之前,已经学习到了线程的创建和状态控制,但是每个线程之间几乎都没有什么太大的联系.可是有的时候,可能存在多个线程多同一个数据进行操作,这样,可能就会引用各种奇怪的问题.现在就来学习多线程对数据访问的 ...

  2. JAVA多线程线程同步问题

    线程同步 在多线程的编程环境下,可能看着没有问题的代码在运行几千上万或者更多次后,出现了一些看着很奇怪的问题,出现这样的问题的原因就是可能会有两个或者更多个线程进入了同一块业务处理代码中导致了判断失效 ...

  3. Java多线程:线程同步与关键字synchronized

    一.同步的特性1. 不必同步类中所有的方法, 类可以同时拥有同步和非同步方法.2. 如果线程拥有同步和非同步方法, 则非同步方法可以被多个线程自由访问而不受锁的限制. 参见实验1:http://blo ...

  4. Java多线程—线程同步(单信号量互斥)

    JDK中Thread.State类的几种状态 线程的生命周期         线程的安全问题(同步与互斥) 方法一:同步代码块 多个线程的同步监视器(锁)必须的是同一把,任何一个类的对象都可以 syn ...

  5. Java多线程-线程的同步(同步方法)

    线程的同步是保证多线程安全访问竞争资源的一种手段.线程的同步是Java多线程编程的难点,往往开发者搞不清楚什么是竞争资源.什么时候需要考虑同步,怎么同步等等问题,当然,这些问题没有很明确的答案,但有些 ...

  6. Java多线程——线程之间的同步

    Java多线程——线程之间的同步 摘要:本文主要学习多线程之间是如何同步的,如何使用volatile关键字,如何使用synchronized修饰的同步代码块和同步方法解决线程安全问题. 部分内容来自以 ...

  7. java 多线程—— 线程让步

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

  8. java 多线程—— 线程等待与唤醒

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

  9. Java 并发 线程同步

    Java 并发 线程同步 @author ixenos 同步 1.异步线程本身包含了执行时需要的数据和方法,不需要外部提供的资源和方法,在执行时也不关心与其并发执行的其他线程的状态和行为 2.然而,大 ...

随机推荐

  1. 用Python xlwt建立excel表格

    1.下载xlwt的Python库 (This is a library for developers to use to generate spreadsheet files compatible w ...

  2. 测试一个服务器的性能,客户要求向数据库(Sqlserver2012)内 1000/s(每插入一千条数据) 的处理能力

    通过jmeter很简单就可以完成,可以参考我以前的一篇文章<jmeter创建数据库(Sqlserver2012)测试>. 前提条件:一个数据库:test   数据库下面有一张表:user  ...

  3. 程序运行时 0xC0000005: 读取位置 0x00000000 时发生访问冲突 ,可能是 com 组件引入各种问题

    在使用com组件事,可能引入很多不是问题的问题,比如CString 定义出运行时出错等等,这些问题解决的办法就是初始化组件 然后释放组件, 在使用组件时,如果仅仅用在按钮事件或者别的mfc 对话框类里 ...

  4. py, pyc, pyw, pyo, pyd 及发布程序时的选择 Compiled Python File (.pyc)

    Python 程序扩展名(py, pyc, pyw, pyo, pyd)及发布程序时的选择 - 司开星的专栏 - CSDN博客 https://blog.csdn.net/chroming/artic ...

  5. runtime(二)

    前言 上一篇中我们大致的了解了runtime的一些基本概念,这一篇我们一起来看看如何使用它. 3.如何使用runtime. 3.1 方法交换 举一个老生常谈的例子.当你接手一个新的项目,需要查看这个程 ...

  6. 为什么要使用nonlocal

    Python3中加入了新的关键字nonlocal,当在一个嵌套的函数中对变量申明为nonlocal时,就明确表示这个变量是外部函数中定义的变量.也许会有这么一个问题:按照python的LEGB原则,在 ...

  7. Pycharm如何修改背景图(BackgroundColor)

    Outline 之前见到别人Eclipse自定义设置了背景图,在想 Pycharm是不是也可以设置?都是IDE嘛~ 没事捣鼓 Pycharm Settings 时,看到“Background Imag ...

  8. 使用Kotlin进行Android开发

     Kotlin是一门基于JVM的编程语言,它正成长为Android开发中用于替代Java语言的继承者.Java是世界上使用最多的编程语言之一,当其他编程语言为更加便于开发者使用而不断进化时,Java并 ...

  9. WireShark告诉你ping百度时都发生了什么

    备注:  测试机器为Mac 重点展示本机发出icmp的过程(dns-->arp-->icmp) 本机默认网关 ->route -n get e -n get default rout ...

  10. CoreThink开发(十)把官方首页轮播替换成HTML5-3D轮播

    效果: 资源已经上传到我的下载里边. http://download.csdn.net/detail/u012995856/9587206 1.复制资源文件到CoreThink项目中 corethin ...