java 被唤醒的线程能重新得到锁么

java 被唤醒的线程能重新得到锁么,第1张

一个被wait后,即使它被notify,它后面的大段代码是继续执行啊。

你这个程序是通过bShouldSub来控制两个方法被交互执行的。

wait就是当前线程被阻塞,直到被另一个线程notify(唤醒),然后当前进程继续执行上次未完成的 *** 作。

下面是API里面写的:

The current thread must own this object's monitor The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up either through a call to the notify method or the notifyAll method The thread then waits until it can re-obtain ownership of the monitor and resumes execution

对象是一个锁标志。按照先到先得的原则,如果有多个线程都会执行代码,并使用同一个对象作为锁,

synchronize(对象){

}

那么,先执行这段代码的那个线程,将会获得这个对象锁,而当这个线程执行这段代码的时候,其他线程也是使用这个对象作为锁的,就不能执行这段代码,知道最初得到这个锁的线程运行完这段代码,然后再把锁分配给下一个线程执行。

死锁是这样一种情形:多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不可能正常终止。

导致死锁的根源在于不适当地运用“synchronized”关键词来管理线程对特定对象的访问。“synchronized”关键词的作用是,确保在某个时刻只有一个线程被允许执行特定的代码块,因此,被允许执行的线程首先必须拥有对变量或对象的排他性的访问权。当线程访问对象时,线程会给对象加锁,而这个锁导致其它也想访问同一对象的线程被阻塞,直至第一个线程释放它加在对象上的锁。

由于这个原因,在使用“synchronized”关键词时,很容易出现两个线程互相等待对方做出某个动作的情形。代码一是一个导致死锁的简单例子。

//代码一

class Deadlocker {

int field_1;

private Object lock_1 = new int[1];

int field_2;

private Object lock_2 = new int[1];

public void method1(int value) {

“synchronized” (lock_1) {

“synchronized” (lock_2) {

field_1 = 0; field_2 = 0;

}

}

}

public void method2(int value) {

“synchronized” (lock_2) {

“synchronized” (lock_1) {

field_1 = 0; field_2 = 0;

}

}

}

}

参考代码一,考虑下面的过程:

◆ 一个线程(ThreadA)调用method1()。

◆ ThreadA在lock_1上同步,但允许被抢先执行。

◆ 另一个线程(ThreadB)开始执行。

◆ ThreadB调用method2()。

◆ ThreadB获得lock_2,继续执行,企图获得lock_1。但ThreadB不能获得lock_1,因为ThreadA占有lock_1。

◆ 现在,ThreadB阻塞,因为它在等待ThreadA释放lock_1。

◆ 现在轮到ThreadA继续执行。ThreadA试图获得lock_2,但不能成功,因为lock_2已经被ThreadB占有了。

◆ ThreadA和ThreadB都被阻塞,程序死锁。

当然,大多数的死锁不会这么显而易见,需要仔细分析代码才能看出,对于规模较大的多线程程序来说尤其如此。好的线程分析工具,例如JProbe Threadalyzer能够分析死锁并指出产生问题的代码位置。

隐性死锁

隐性死锁由于不规范的编程方式引起,但不一定每次测试运行时都会出现程序死锁的情形。由于这个原因,一些隐性死锁可能要到应用正式发布之后才会被发现,因此它的危害性比普通死锁更大。下面介绍两种导致隐性死锁的情况:加锁次序和占有并等待。

加锁次序

当多个并发的线程分别试图同时占有两个锁时,会出现加锁次序冲突的情形。如果一个线程占有了另一个线程必需的锁,就有可能出现死锁。考虑下面的情形,ThreadA和ThreadB两个线程分别需要同时拥有lock_1、lock_2两个锁,加锁过程可能如下:

◆ ThreadA获得lock_1;

◆ ThreadA被抢占,VM调度程序转到ThreadB;

◆ ThreadB获得lock_2;

◆ ThreadB被抢占,VM调度程序转到ThreadA;

◆ ThreadA试图获得lock_2,但lock_2被ThreadB占有,所以ThreadA阻塞;

◆ 调度程序转到ThreadB;

◆ ThreadB试图获得lock_1,但lock_1被ThreadA占有,所以ThreadB阻塞;

◆ ThreadA和ThreadB死锁。

必须指出的是,在代码丝毫不做变动的情况下,有些时候上述死锁过程不会出现,VM调度程序可能让其中一个线程同时获得lock_1和lock_2两个锁,即线程获取两个锁的过程没有被中断。在这种情形下,常规的死锁检测很难确定错误所在。

占有并等待

如果一个线程获得了一个锁之后还要等待来自另一个线程的通知,可能出现另一种隐性死锁,考虑代码二。

//代码二

public class queue {

static javalangObject queueLock_;

Producer producer_;

Consumer consumer_;

public class Producer {

void produce() {

while (!done) {

“synchronized” (queueLock_) {

produceItemAndAddItToQueue();

“synchronized” (consumer_) {

consumer_notify();

}

}

}

}

public class Consumer {

consume() {

while (!done) {

“synchronized” (queueLock_) {

“synchronized” (consumer_) {

consumer_wait();

}

removeItemFromQueueAndProcessIt();

}

}

}

}

}

}

在代码二中,Producer向队列加入一项新的内容后通知Consumer,以便它处理新的内容。问题在于,Consumer可能保持加在队列上的锁,阻止Producer访问队列,甚至在Consumer等待Producer的通知时也会继续保持锁。这样,由于Producer不能向队列添加新的内容,而Consumer却在等待Producer加入新内容的通知,结果就导致了死锁。

在等待时占有的锁是一种隐性的死锁,这是因为事情可能按照比较理想的情况发展—Producer线程不需要被Consumer占据的锁。尽管如此,除非有绝对可靠的理由肯定Producer线程永远不需要该锁,否则这种编程方式仍是不安全的。有时“占有并等待”还可能引发一连串的线程等待,例如,线程A占有线程B需要的锁并等待,而线程B又占有线程C需要的锁并等待等。

要改正代码二的错误,只需修改Consumer类,把wait()移出“synchronized”()即可。

1公平所和非公平所。

公平锁:是指按照申请锁的顺序来获取锁,

非公平所:线程获取锁的顺序不一定按照申请锁的顺序来的。

//默认是不公平锁,传入true为公平锁,否则为非公平锁

ReentrantLock reentrantLock = new ReetrantLock();

1

2

2共享锁和独享锁

独享锁:一次只能被一个线程所访问

共享锁:线程可以被多个线程所持有。

ReadWriteLock 读锁是共享锁,写锁是独享锁。

3乐观锁和悲观锁。

乐观锁:对于一个数据的 *** 作并发,是不会发生修改的。在更新数据的时候,会尝试采用更新,不断重入的方式,更新数据。

悲观锁:对于同一个数据的并发 *** 作,是一定会发生修改的。因此对于同一个数据的并发 *** 作,悲观锁采用加锁的形式。悲观锁认为,不加锁的 *** 作一定会出问题,

4分段锁

17及之前的concurrenthashmap。并发 *** 作就是分段锁,其思想就是让锁的粒度变小。

5偏向锁是指一段同步代码一直被一个线程所访问,那么该线程会自动获取锁。降低获取锁的代价

轻量级锁

重量级锁

6自旋锁

自旋锁

以上就是关于java 被唤醒的线程能重新得到锁么全部的内容,包括:java 被唤醒的线程能重新得到锁么、java加锁、如何通过编程发现Java死锁等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/9749099.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-01
下一篇2023-05-01

发表评论

登录后才能评论

评论列表(0条)

    保存