第十三章 线程安全与锁优化

一、线程安全

线程安全:指当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调用和交替执行,也不需要进行额外的同步,或者在调用方法进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那么喝个对象就是线程安全的。

1.Java语音中的线程安全

我们可以根据线程安全的“安全程度”由强至弱来排序呢,将Java语音中各种操作共享的数据分为五类

  • 1.不可变

  • 2.绝对线程安全

  • 3.相对线程安全

  • 4.线程兼容

  • 5.线程独立

不可变

不可变对象一定是线程安全的,因为它根本不变,比如final、 String、 枚举、Long、Double、BigInteger等

绝对线程安全

绝对的东西应该很少存在,如果想实现绝对线程安全是要付出巨大代价的,甚至有些情况下根本不可能实现绝对线程安全。在Java API中标榜自己是线程安全的类,大多数都不会绝对的线程安全。我们知道,java.util.Vector是一个线程安全的容器,它的add()/get()/size()方法都是被synchronized修饰的,尽管这样效率很低,但是确实是安全的。悲剧的是,即使它所有的方法都被修饰成synchronized,也不意味着调用它的时候永远都不再需要同步手段了。下面就是打脸时刻

相对线程安全

相对线程安全就是通常意义上的线程安全,它需要保证对这个对象的单独操作是线程安全的,我们在调用的时候不需要做额外的保障措施,但是对于多个线程的调用,就需要在调用端使用额外的同步手段来保证调用的正确性。

在Java语言中,大部分的线程安全类都属于这种类型,例如Vector、HashTable、Collections的synchronizedCollection()方法包装的集合等

线程兼容

线程兼容是指对象本身并不是线程安全的,但是可以通过在调用端使用同步手段来保证对象在并发环境中安全滴使用。我们平常说一个类不是线程安全的,就是指这种情况。Java API中大部分的类都是线程兼容的,比如ArrayList和HashMap(非线程安全,说的就是你!原来是线程兼容的呀)等。

二、线程安全的实现方法

互斥同步

互斥同步是最常见的一种并发正确性保证手段。在Java里,最基本的互斥同步手段就是synchronized关键字.synchronized关键字经过编译后,会在同步块的前后分别形成monitorenter和monitorext这两个字节码指令,

synchronized的工作原理

  • 1.synchronized 相当于一个标志,每个对象都有对象头,对象头中含有锁信息(也称为监视器)。每次使用某个对象时,会去检查是否被synchronized修饰,如果修饰了,就去看看当前对象是否获取了锁,如果没有,就阻塞;如果获取了,就可以进行对应的逻辑。等执行完之后,就释放当前对象使用的锁。

  • 2.还有一个比较好玩的是对象头中的锁不是boolean类型,意思就是锁可以技术。一个获取当前对象的锁方法,可以调用另一个synchronized的方法,这时锁计数就是2,当锁的计数变成0,就该释放锁了。

  • 3.针对每个类,也有一个锁,所以synchronized static 方法可以在类的范围内防止对static数据的并发访问。

Lock的使用

Java SE5的 java.util.concurrent 类库还包含有定义在 java.util.concurrent.locks 中的显式的互斥机制。Lock 对象必须显式的创建、锁定和释放。因此,它与 synchronized 提供的锁机制相比,代码缺少优雅性。但是对于有些场景,使用 Lock 会更加灵活。

如何优雅的关闭任务?

对应于任务的关闭,一般有两种方式:

  • 任务正常运行,正常关闭

  • 出现紧急情况,需要终止当前任务

猜你喜欢

转载自blog.csdn.net/feirose/article/details/60958705