八、并发编程之重入锁、自旋锁、死锁

1、重入锁

  • 重入锁:能够让线程进行重入的锁叫作重入锁,也叫递归锁,在JAVA环境下 ReentrantLock 和synchronized 都是可重入锁。
  • 锁重入:某个线程获得一个已经由它自己持有的锁对象,那么这个请求就会成功,即重入。重入是对本线程来说,即本线程多资源可以多次加锁进入,而不会出现阻塞。
  • 锁重入现象:
    1.当进入a方法的时候,线程必须先拿到当前类的实例(锁),这个时候,a的方法内同时调用了b方法,b方法也是用synchronized来修饰的,所以b方法也需要线程获取锁才能让线程进来。这时候会不会发生进入了a方法,而不能进入b方法的现象呢?
    答案是:不会,因为进入a方法的时候,线程拿的锁是当前类的实例(锁),当线程要进入b方法的时候,线程拿的锁也是当前类的实例(锁),前一把锁和后一把锁都是同一个把锁,这个时候就发生了锁重入现象
    2.当一个线程拿到当前类的实例(锁)调用a方法,这个时候另外一个线程调用b方法,会不会等待?
    答案是:如果两个线程里是是同一个对象调用方法,才能够锁的住,需要等待,如果是不同的对象锁不住,不需要等待。
public class Demo {
	public synchronized void a () {
		System.out.println("a");
		b();
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	public synchronized void b() {
		System.out.println("b");
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		Demo d1= new Demo();
		Demo d2= new Demo();
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				d1.a();
			}
		}).start();
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				//d1.b();//需要等待,因为d1的锁已经被另外一个线程拿到了
				d2.b();//不用等待,拿到了d2的锁
			}
		}).start();
	}
}

2、自旋锁

可以理解成线程进入了while(true){}中,CPU在空转,消耗性能。一般发生在多线程需要进入synchronized修饰的方法,只有一个线程能获取锁,其他线程很有可能都发生自旋现象。

/**
 * 多个线程执行完毕之后,打印一句话,结束
 */
public class Demo2 {
	public static void main(String[] args) {
		//第一个线程
		new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println(Thread.currentThread().getName() + " 线程执行...");
				try {
					Thread.sleep(new Random().nextInt(2000));
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName() + " 线程执行完毕了...");
			}
		}).start();
		//第二个线程
		new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println(Thread.currentThread().getName() + " 线程执行...");
				try {
					Thread.sleep(new Random().nextInt(2000));
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName() + " 线程执行完毕了...");
			}
		}).start();
		//第三个线程
		new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println(Thread.currentThread().getName() + " 线程执行...");
				try {
					Thread.sleep(new Random().nextInt(2000));
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName() + " 线程执行完毕了...");
			}
		}).start();
		//第四个线程
		new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println(Thread.currentThread().getName() + " 线程执行...");
				try {
					Thread.sleep(new Random().nextInt(2000));
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName() + " 线程执行完毕了...");
			}
		}).start();
		//第五个线程
		new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println(Thread.currentThread().getName() + " 线程执行...");
				try {
					Thread.sleep(new Random().nextInt(2000));
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName() + " 线程执行完毕了...");
			}
		}).start();
		while(Thread.activeCount() != 1) {//当前活动线程的数量,程序没有执行完毕
			// 自旋,空转CPU
		}
		System.out.println("所有的线程执行完毕了...");
	}
}

3、死锁

源互斥导致互相占用不放

public class Demo3 {
	private Object obj1 = new Object();
	private Object obj2 = new Object();
	
	public void a () {
		synchronized (obj1) {
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			synchronized (obj2) {
				System.out.println("a");
			}
		}
	}
	
	public void b () {
		synchronized (obj2) {
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			synchronized (obj1) {
				System.out.println("b");
			}
		}
	}
	
	public static void main(String[] args) {
		Demo3 d = new Demo3();
		new Thread(new Runnable() {
			@Override
			public void run() {
				d.a();
			}
		}).start();
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				d.b();
			}
		}).start();
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值