阿特我自己
[email protected]
Hello WvT
16.5 线程同步
16.5 线程同步

1. 线程安全问题

多线程很容易出现安全问题,举个例子,

甲乙两人同时对同一个账户进行取钱操作,账户只有1元钱。此时可能会出现多线程的同步问题,如:

甲成功取出1元钱,但余额尚未修改,同时乙试图取出1元钱,仍会成功取出。

接下来,甲乙线程都执行到余额修改处,同时扣除1元,此时余额为-1元,而这并不是期望结果。

2. 同步代码块

Java 引入了同步监视器来解决线程安全问题,使用同步监听器的通用方法就是同步代码块,语法格式如下

上方代码的含义是:当线程开始执行同步代码块之前,必须获得对同步监视器 (obj) 的锁定

任何时刻只能有一个线程可以获得对同步监视器的锁定,当代码块执行完毕后,该线程会释放对该同步监视器的锁定

如果一个线程正在获取已锁定的同步监视器,该线程会被阻塞直到获取到同步监视器

3. 同步方法

使用 synchronized 关键字修饰方法,同步监视器为 this,即调用该方法的对象

通过使用同步方法可以非常方便地实现线程安全类,线程安全的类具有如下特征

  • 该类的对象可以被多个线程安全地访问
  • 每个线程调用该对象的任意方法之后都将得到正确的结果
  • 每个线程调用该对象的任意方法后,该对象状态依然保持合理状态

不可变类总是线程安全的

线程安全是以性能为代价的,为减少负面影响,程序应采用如下策略:

  • 不要对线程安全类的所有方法都进行同步,只对那些会竞争资源的方法进行同步
  • 如果可变类有两种运行环境:单线程环境和多线程环境,程序应该为该类提供两种版本以保证性能

4. 释放同步监听器的锁定

程序无法显式释放锁定,但线程会在如下几种情况下释放对同步监听器的锁定

  • 当前线程的同步方法、同步代码块执行结束
  • 当前线程在同步方法、同步代码块遇到 breakreturn 终止了该代码块或方法
  • 当前线程在同步方法、同步代码块中出现了未处理的 ErrorException 导致该代码块、该方法结束
  • 当前线程执行同步方法、同步代码块时,程序执行了同步监听器对象的 wait() 方法,当前线程暂停

在如下情况下,线程不会释放同步监听器的锁定

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

5. 同步锁(Lock)

从 Java5 开始,Java 提供了一种功能更强大的线程同步机制——通过显示定义同步对象来实现同步,在这种机制下,同步锁由 Lock 对象充当

LockReadWriteLock 是 Java5 提供的两个根接口

Lock 接口有 ReentrantLockReentrantLock 实现类

ReadWriteLock 接口有 ReentrantReadWriteLock 实现类

Java 8 新增了 StampedLock 类可以替代传统的 ReentrantReadWriteLock

在实现线程安全的控制中,常用的是 ReentrantLock(可重入锁)

使用其实例的 lock() 方法加锁,unLock() 方法释放锁,与使用 synchronized 修饰符相似

6. 死锁

当两个线程相互等待对方释放同步监听器时就会发生死锁,所有线程将处于阻塞状态

Java虚拟机没有监测,也没有措施来处理死锁,因此在编写代码时务必注意这种情况

赞赏

发表评论

textsms
account_circle
email

Hello WvT

16.5 线程同步
1. 线程安全问题 多线程很容易出现安全问题,举个例子, 甲乙两人同时对同一个账户进行取钱操作,账户只有1元钱。此时可能会出现多线程的同步问题,如: 甲成功取出1元钱,但余额…
扫描二维码继续阅读
2018-11-11


没有激活的小工具