罗湖做网站公司,net和cn哪个做网站好,本地怎样做网站,无锡网站怎么优化排名什么是线程死锁
线程死锁是指由于两个或者多个线程互相持有对方所需要的资源#xff0c;导致这些线程处于相互等待状态#xff0c;若无外力作用#xff0c;它们将无法继续执行下去。
造成死锁的原因可以概括成三句话#xff1a;
当前线程拥有其他线程需要的资源当前线程…什么是线程死锁
线程死锁是指由于两个或者多个线程互相持有对方所需要的资源导致这些线程处于相互等待状态若无外力作用它们将无法继续执行下去。
造成死锁的原因可以概括成三句话
当前线程拥有其他线程需要的资源当前线程等待其他线程已拥有的资源都不放弃自己拥有的资源
线程死锁产生的四个必要条件
互斥共享资源 X 和 Y 只能被一个线程占用占有且等待线程 T1 已经取得共享资源 X在等待共享资源 Y 的时候不释放共享资源 X不可抢占其他线程不能强行抢占线程 T1 占有的资源循环等待线程 T1 等待线程 T2 占有的资源线程 T2 等待线程 T1 占有的资源就是循环等待。
举个必然产生死锁的例子
public static void main(String[] args) {Object a new Object();Object b new Object();// 线程1new Thread(() - {synchronized (a) {System.out.println(获得了A锁);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (b) {}}}).start();// 线程2new Thread(() - {synchronized (b) {System.out.println(获得了B锁);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (a) {}}}).start();
}上面的程序就是一个典型死锁的例子为了保证死锁发生的几率我这里在获得锁之后睡眠了1s。
线程1在获得A对象锁之后等了1s去尝试获取B对象锁这时线程1是持有A对象锁的线程2在获得B对象锁之后等待1s去尝试获得A对象锁这时线程2是持有B对象锁的就在它们彼此想获得对方的锁的时候死锁发生了并且一直持续下去。
如何避免死锁
上面提到只有这四个条件都发生时才会出现死锁那么意思就是说只要我们破坏其中一个就可以成功预防死锁的发生。
破坏互斥只有一把锁这是形成死锁的最关键的原因。显然如果我们能在两个线程跑之前能给每个线程单独拷贝一份钥匙的副本就能有效的避免死锁了。占用且等待一次性申请所有的资源这样就不存在等待了。 例如线程1一次性拿到A和B两个锁线程2在获取锁的时候需要等待线程1释放锁这样就避免了多线程互相占用等待的情况。不可抢占占用部分资源的线程进一步申请其他资源时如果申请不到可以主动释放它占有的资源。 在上面的死锁代码中我们使用了synchronized关键字它是不能主动释放资源的会造成线程一直阻塞JUC提供了Lock解决这个问题。 显式使用Lock类中的定时tryLock功能来代替内置锁机制可以检测死锁和从死锁中恢复过来。显式锁可以指定一个超时时限Timeout在等待超过该时间后tryLock就会返回一个失败信息释放其拥有的资源其他线程可以获取此资源避免死锁。循环等待如果一个线程需要一些锁那么它必须按照确定的顺序获取锁。只有先获得了从顺序上排在前面的锁之后才能获取后面的锁。 破坏循环条件很简单只要线程之间不要出现交叉占用的情况即可也就是说在在代码中尽量避免线程1保持A请求B线程2保持B请求A尽可能使他们请求的顺序一致比如线程1请求的顺序是A、B线程2请求的顺序也是A、B这样自然就避免了循环等待的情况发生。
总结
死锁是一个比较头疼的问题但是只要我们的代码规范可以避免大多数情况下的死锁。还有避免死锁的经典算法是银行家算法这里就不扩开介绍了。
在很多情况下尤其是多线程编程中我们要注意线程之间的资源是否存在互相竞争的情况如果有要及时规避死锁的风险。
死锁很多时候会发生在数据库操作中例如长事务、并发条件下的共享锁升级等都会造成数据库死锁后面有时间会专门针对数据库死锁讲一讲。