目录
1.线程死锁
1.基本介绍
多个线程占用了对方放入锁资源,但不肯相让,导致了死锁,在编程里面是一定要避免死锁的发生。
2.应用案例
public class DeadLock_ {
public static void main(String[] args) {
//模拟死锁现象
DeadLockDemo deadLockDemo=new DeadLockDemo(true);
DeadLockDemo deadLockDemo1 = new DeadLockDemo(false);
deadLockDemo1.start();
deadLockDemo.start();
}
}
class DeadLockDemo extends Thread{
static Object o1=new Object();
static Object o2=new Object();
boolean flag;
public DeadLockDemo(boolean flag){
this.flag=flag;
}
@Override
public void run() {
//如果flag为true,线程就会现持有o1对象锁,然后尝试去获取o2对象锁
//如果线程a得不到o2的对象锁,就会Blocked
//如果flag为False
//如果线程b得不到o1的对象锁,就会Blocked
if(flag){
synchronized (o1) {
System.out.println(Thread.currentThread().getName() + "进入1");
synchronized (o2) {
System.out.println(Thread.currentThread().getName()+"进入2");
}
}
}
else{
synchronized (o2) {
System.out.println(Thread.currentThread().getName()+"进入3");
synchronized (o1){
System.out.println(Thread.currentThread().getName()+"进入4");
}
}
}
}
}
这里我们还是一样,继承Thread实现线程。在run方法里面我们实现了模拟死锁的代码。我们用if-else语句在其中添加了两个嵌套互斥锁模块。分别是:
synchronized (o1) {
System.out.println(Thread.currentThread().getName() + "进入1");
synchronized (o2) {
System.out.println(Thread.currentThread().getName()+"进入2");
}
}
synchronized (o2) {
System.out.println(Thread.currentThread().getName()+"进入3");
synchronized (o1){
System.out.println(Thread.currentThread().getName()+"进入4");
}
}
在主函数开启Thread-0,Thread-1两个线程的时候,我们会发现他们分别同时获得了o1和o2两把锁,但要下一步的时候,我们发现无法执行下一步,因为Thread-0需要o2的锁,而Thread-1需要o1的锁。但他们都不肯放掉,所以他们就卡在这一步了。这种情况我们一般称为线程死锁。运行结果如下:
但如果代码如下:
public class DeadLock_ {
public static void main(String[] args) {
//模拟死锁现象
DeadLockDemo deadLockDemo=new DeadLockDemo(true);
DeadLockDemo deadLockDemo1 = new DeadLockDemo(false);
deadLockDemo1.start();
deadLockDemo.start();
}
}
class DeadLockDemo extends Thread{
static Object o1=new Object();
static Object o2=new Object();
boolean flag;
public DeadLockDemo(boolean flag){
this.flag=flag;
}
@Override
public void run() {
//如果flag为true,线程就会现持有o1对象锁,然后尝试去获取o2对象锁
//如果线程a得不到o2的对象锁,就会Blocked
//如果flag为False
//如果线程b得不到o1的对象锁,就会Blocked
if(flag){
synchronized (o1) {
System.out.println(Thread.currentThread().getName() + "进入1");
}
synchronized (o2) {
System.out.println(Thread.currentThread().getName()+"进入2");
}
}
else{
synchronized (o2) {
System.out.println(Thread.currentThread().getName()+"进入3");
}
synchronized (o1){
System.out.println(Thread.currentThread().getName()+"进入4");
}
}
}
}
结果如下:
你会发现他并没有被锁上,因为在Thread-0需要o2的锁时,他o1的锁已经不需要了,也就放开了。Thread-1也是一样,所以他们并没有处于死锁的状态中。所以我们可以知道,在线程死锁的情况下,线程处于无锁可用的情况下。当然,死锁是一种很恐怖的情况,所以我们一般是避免这种情况。
2.释放锁
1.以下情况会释放锁:
-
当前线程的同步方法,同步代码块执行结束。
-
当前线程在同步代码块,同步方法中遇到break,return
-
当前线程在同步代码块,同步方法中出现了未处理的Error或Exception,导致异常结束
-
当前线程在同步代码块,同步方法中执行了线程对象的wait()方法,当线程暂停,并释放锁
2.以下操作不会释放锁:
-
线程在执行同步代码块或同步方法时,程序调用Thread.sleep(),Thread.yield()方法暂停当前线程的执行,不会释放锁。
-
线程执行同步代码时,其他线程调用了该线程的suspend()方法将该线程挂起,该线程不会释放锁。ps:尽量避免使用suspend()和resume()来控制线程