多线程操作同一个对象时,容易引发线程安全问题。为了解决线程安全问题,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. 用RSS订阅微信公众号

    现在用RSS的人应该不多了,不过还是写一下吧. 一.付费服务:今天看啥 1.付费原因: 目前,网上几乎没有免费的用RSS订阅微信公号的方法,所以我推荐的是付费方法: 具体使用的服务是今天看啥,服务还是 ...

  2. angular.js记录

    http://www.runoob.com/angularjs/angularjs-tutorial.html 第一部分:快速上手1.1 angularJS四大核心特性1.2 自己动手搭建开发,调试, ...

  3. [科普]什么是SysWow64

    Wow!什么是Wow64 今天有个同事,被SysWow64搞晕了.这里简单介绍一下. 64位的Windows并不是简单地把所有东西都编译成64位就万事大吉的.关于64位的CPU应该做成什么样子,Int ...

  4. FFMPEG推流到RTMP服务器命令 - weixin_37897683的博客 - CSDN博客 https://blog.csdn.net/weixin_37897683/article/details/81225228

    FFMPEG推流到RTMP服务器命令 - weixin_37897683的博客 - CSDN博客 https://blog.csdn.net/weixin_37897683/article/detai ...

  5. Unicode 和 UTF-8 是什么关系?

    2015-10-14 10:08    评论: 9 收藏: 4 转载自: http://huoding.com/2015/10/13/472作者: 火丁笔记本文地址:https://linux.cn/ ...

  6. ViewConfiguration 和 ViewConfigurationCompat

    Contains methods to standard constants used in the UI for timeouts, sizes, and distances. 一.几个常用的方法 ...

  7. weal woe

    He is worth no weal that can bide no woe. 禁不起吃苦的人不配得到幸福 有句谚语叫No weal without woe 福兮祸所伏 ; 祸兮福所倚 weal和 ...

  8. 重置Linux普通账号和root账号密码

    今天想在Linux测试下HTTPie, 突然发现虚拟机里面的Linux, root账号和普通账号密码都忘记了. 百度了半天发现答案都不对, 最后用Google搜到了答案. 本人系统环境: VMware ...

  9. go——流程控制

    Go在流程控制方面的特点如下: 没有do和while循环,只有一个更广义的for语句. switch语句灵活多变,还可以用于类型判断. if语句和switch语句都可以包含一条初始化子语句. brea ...

  10. LeetCode:括号的分数【856】

    LeetCode:括号的分数[856] 题目描述 给定一个平衡括号字符串 S,按下述规则计算该字符串的分数: () 得 1 分. AB 得 A + B 分,其中 A 和 B 是平衡括号字符串. (A) ...