多线程的一些问题
来源:互联网 发布:mac用pe安装win7系统 编辑:程序博客网 时间:2024/06/05 12:02
保证线程安全的基本知识:
读写失效:
多线程操作一个变量时,仅仅对set操作进行同步是不够的,必须对get操作也进行同步,这是因为仅对set进行同步无法保证变量的可见性。即两个线程分别对一个变量进行读操作和写操作时,可能读到失效值。而且jvm可能对程序进行重新排序,影响多线程的逻辑。
double和long是64位变量,在进行读写操作时会被分成两个32位进行,所以不是原子操作。所以多线程中使用这种类型必须添加volatile
volatile保证了内存可见性,当满足以下条件时可以用:访问该变量时不需要加锁,变量不会与其他变量一起纳入不变性条件中,对变量的写操作不依赖当前值(或者只有一个线程进行写操作)
逸出:
一个对象(类)中的任何域不论以什么方式发布出去,可以被外界访问到,都是逸出。包括公有的方法,添加到容器中,甚至是方法中的内部类调用了该对象的方法。这些都会导致外部可以间接的访问到对象中的域,使其线程不安全。逸出可以传递(逸出的域中如果有公有的域或者方法,这些也会被发布)
线程封闭:
1.栈封闭 : 在方法中使用局部变量来达到线程封闭。基本类型不会逸出,引用类型需要注意不要逸出。
2.ThreadLocal类
不变性:利用不可变对象和volatile来控制并发。不可变对象是线程安全的,但是也是可以更新的,更新方法是用新的对象替换老的。这时用volatile来控制可见性就可以达到目的。
利用一些组件实现线程安全:
在实时线程安全时,需要考虑先验条件,后验条件,不变性条件(属性之间的依赖)。一旦发布一个对象后,这个对象的所有权将会转移或者被共享。
对象的封装:将一个对象a封装到另一个对象b中,a的所有访问途径必须通过b来实现。b中可以利用锁的同步策略实行同步。因此即使a不是线程安全的,但是b是线程安全的,也可以保证a的并发安全性。前提是a不能被发布。
委托:当类中的状态全部由线程安全的类管理时,如果各个状态彼此独立不存在依赖,则这个类也是线程安全的。 但如果状态之间存在不变性条件,则需要添加同步策略。
在现有的线程安全的类上添加方法:1.扩展 : 新的类封装旧的安全类,同时添加新的方法,注意新方法的锁应该用封装的类的锁 2.组合 : 与原来的类实现同样的接口,方法的实现均调用旧类的方法,但在新的方法上添加对象锁,同时自己新实现的方法也要添加对象锁(组合并不关心底层是不是线程安全的)
并发容器
迭代器一定要加锁,否则会出现concurrentModificationException
几种控制并发流程的工具 1.闭锁CountDownLatch 2.FutureTask 3.信号量Semaphore
死锁
嵌套的获得两个锁,如果顺序不当会引发死锁。如方法一和方法二分别以相反的顺序获得锁1和锁2,那么在两个线程同时调用这两个方法时会死锁。
动态的顺序也有一定几率出现死锁。如果两个线程分别以相反的参数调用同一个方法,每个参数都有一个锁,有可能死锁。解决方案是利用hashcode值以固定顺序获取锁。
如果出现hashcode相等的情况,可以在类中添加一个额外的对象(加时锁),用来表示特殊情况,这时方法需要获取三个锁
这种情况不光会发生在一个方法上,还有可能出现在两个对象协作的时候。第一个对象调用自身的同步方法,方法中需要掉到第二个对象的某个同步方法。第二个对象同样,这样就可能出现死锁。
线程饥饿死锁:线程池 有界线程池/资源池 不能与相互依赖的任务一起使用
开放调用:调用某个方法时不需要持有锁。 尽可能使用开放调用,使用同步代码块减小同步的代码范围
避免死锁的方法:
1.开放调用 2.获取多个锁时固定顺序 3.可以设置超时的显式锁
其他的影响性能的问题:活锁 (信道发包冲突,会随机延迟一段时间防止再一次冲突) 饥饿
显示锁Lock
所有的加锁和解锁都是显式的,内存可见性语义与内置锁相同。但性能,算法,顺序等可能不同。
内置锁必须在获取锁的代码块中释放,无法中断一个正在获取锁的请求。Lock实现了一种更为灵活的加锁机制。
一定要在finally中释放锁,否则该锁将永远无法释放。还要做好异常处理。这是Lock比同步代码块危险的地方。
利用tryLock()实现轮询锁和定时锁,tryLock可以添加时间作为参数
lock.lockInterruptubly()是一个可中断的获取锁的操作,抛出InterruptedException.
ReentrantLock与内置锁在java6以后性能近乎相同
锁可以是公平的或者非公平的,默认非公平。非公平的锁比公平锁有更好的性能,原因在于非公平锁减少了线程挂起以及唤醒的开销。在公平的前提下,每个线程在获取一个被占有的锁时都会先挂起排队,最终被唤醒。而非公平的锁可以插队,减少了挂起以及唤醒的几率。
除非synchronized不能满足需求,一般情况下优先级大于显示锁 前者是JVM内置属性,可以执行一些优化 而且显示锁操作更易于出错
读写所ReadWriteLock 当锁的持有时间比较长,而且大部分操作都不会修改被守护的资源时,读写锁有较高的性能。
- 多线程的一些问题
- 多线程的一些问题
- 多线程的 一些小问题
- 有关多线程的一些技术问题
- 有关多线程的一些技术问题
- boost python 多线程 纠结的一些问题
- 有关多线程的一些技术问题
- 多线程的一些小问题集锦
- 有关多线程的一些技术问题
- 多线程和socket编程的一些问题
- 关于多线程学习遇到的一些问题
- 这两天看多线程的时候发现的一些问题【修改Mutex多线程同步的问题】
- 关于linux中多线程编程的一些初级问题
- 程序中一些和多线程有关的问题
- 多线程学习第一篇(一些概念性的问题)
- String.CopyTo方法和java多线程的一些问题整理
- Linux下多线程编程遇到的一些问题
- 关于回调函数和多线程的一些问题
- magento中常用知识点
- Hadoop学习第一天
- 计算机类中文核心期刊
- OpenCV Contrib Modules
- 写一个递归函数DigitSum(n),输入一个非负整数,返回组成它的数字之和,例如,调用DigitSum(1729),则应该返回1+7+2+9,它的和是19
- 多线程的一些问题
- 几种关于卷积的深刻而有趣的理解【看过绝对不会再忘了】
- PAT Basic 1010
- 将一个字符串的前n个字符旋转到后面,采用左旋,或者右旋。
- ubuntu系统入门常用命令
- 使用 IDEA 的 Live Template 实现自动提示代码功能
- linux篇之安装jdk环境
- 从贝叶斯方法谈到贝叶斯网络
- Linux 中颜色显示