当前位置: 移动技术网 > IT编程>开发语言>Java > 基于Java信号量解决死锁过程解析

基于Java信号量解决死锁过程解析

2020年10月17日  | 移动技术网IT编程  | 我要评论
死锁在多线程的情况下,会出现数据不同步情况, 而为了避免这种情况,之前也说了:界区实现方法有两种,一种是用synchronized,一种是用lock显式锁实现。而如果不恰当的使用了锁,且出现同时要锁多

死锁在多线程的情况下,会出现数据不同步情况, 而为了避免这种情况,之前也说了:界区实现方法有两种,一种是用synchronized,一种是用lock显式锁实现。

而如果不恰当的使用了锁,且出现同时要锁多个对象时,会出现死锁情况,如下:

package locktest;
import java.util.date;
/**
 * 崔素强
 * @author cuisuqiang@163.com
 */
public class locktest {
	public static string obj1 = "obj1";
	public static string obj2 = "obj2";
	public static void main(string[] args) {
		locka la = new locka();
		new thread(la).start();
		lockb lb = new lockb();
		new thread(lb).start();
	}
}
class locka implements runnable{
	public void run() {
		try {
			system.out.println(new date().tostring() + " locka 开始执行");
			while(true){
				synchronized (locktest.obj1) {
					system.out.println(new date().tostring() + " locka 锁住 obj1");
					thread.sleep(3000); // 此处等待是给b能锁住机会
					synchronized (locktest.obj2) {
						system.out.println(new date().tostring() + " locka 锁住 obj2");
						thread.sleep(60 * 1000); // 为测试,占用了就不放
					}
				}
			}
		} catch (exception e) {
			e.printstacktrace();
		}
	}
}
class lockb implements runnable{
	public void run() {
		try {
			system.out.println(new date().tostring() + " lockb 开始执行");
			while(true){
				synchronized (locktest.obj2) {
					system.out.println(new date().tostring() + " lockb 锁住 obj2");
					thread.sleep(3000); // 此处等待是给a能锁住机会
					synchronized (locktest.obj1) {
						system.out.println(new date().tostring() + " lockb 锁住 obj1");
						thread.sleep(60 * 1000); // 为测试,占用了就不放
					}
				}
			}
		} catch (exception e) {
			e.printstacktrace();
		}
	}
}

看打印:

mon mar 31 10:52:38 cst 2014 locka 开始执行
mon mar 31 10:52:38 cst 2014 locka 锁住 obj1
mon mar 31 10:52:38 cst 2014 lockb 开始执行
mon mar 31 10:52:38 cst 2014 lockb 锁住 obj2

a锁住了b需要的,b锁住了a需要的,此时死锁产生。

为了解决这个问题,我们不使用显示的去锁

信号量可以控制资源能被多少线程访问,这里我们指定只能被一个线程访问,就做到了类似锁住。而信号量可以指定去获取的超时时间,我们可以根据这个超时时间,去做一个额外处理。

对于无法成功获取的情况,一般就是重复尝试,或指定尝试的次数,也可以马上退出。

来看下如下代码:

package locktest;
import java.util.date;
import java.util.concurrent.semaphore;
import java.util.concurrent.timeunit;
/**
 * 崔素强
 * @author cuisuqiang@163.com
 */
public class unlocktest {
	public static string obj1 = "obj1";
	public static final semaphore a1 = new semaphore(1);
	public static string obj2 = "obj2";
	public static final semaphore a2 = new semaphore(1);

	public static void main(string[] args) {
		lockaa la = new lockaa();
		new thread(la).start();
		lockbb lb = new lockbb();
		new thread(lb).start();
	}
}
class lockaa implements runnable {
	public void run() {
		try {
			system.out.println(new date().tostring() + " locka 开始执行");
			while (true) {
				if (unlocktest.a1.tryacquire(1, timeunit.seconds)) {
					system.out.println(new date().tostring() + " locka 锁住 obj1");
					if (unlocktest.a2.tryacquire(1, timeunit.seconds)) {
						system.out.println(new date().tostring() + " locka 锁住 obj2");
						thread.sleep(60 * 1000); // do something
					}else{
						system.out.println(new date().tostring() + "locka 锁 obj2 失败");
					}
				}else{
					system.out.println(new date().tostring() + "locka 锁 obj1 失败");
				}
				unlocktest.a1.release(); // 释放
				unlocktest.a2.release();
				thread.sleep(1000); // 马上进行尝试,现实情况下do something是不确定的
			}
		} catch (exception e) {
			e.printstacktrace();
		}
	}
}
class lockbb implements runnable {
	public void run() {
		try {
			system.out.println(new date().tostring() + " lockb 开始执行");
			while (true) {
				if (unlocktest.a2.tryacquire(1, timeunit.seconds)) {
					system.out.println(new date().tostring() + " lockb 锁住 obj2");
					if (unlocktest.a1.tryacquire(1, timeunit.seconds)) {
						system.out.println(new date().tostring() + " lockb 锁住 obj1");
						thread.sleep(60 * 1000); // do something
					}else{
						system.out.println(new date().tostring() + "lockb 锁 obj1 失败");
					}
				}else{
					system.out.println(new date().tostring() + "lockb 锁 obj2 失败");
				}
				unlocktest.a1.release(); // 释放
				unlocktest.a2.release();
				thread.sleep(10 * 1000); // 这里只是为了演示,所以tryacquire只用1秒,而且b要给a让出能执行的时间,否则两个永远是死锁
			}
		} catch (exception e) {
			e.printstacktrace();
		}
	}
}

看打印情况:

mon mar 31 10:57:07 cst 2014 locka 开始执行
mon mar 31 10:57:07 cst 2014 lockb 开始执行
mon mar 31 10:57:07 cst 2014 lockb 锁住 obj2
mon mar 31 10:57:07 cst 2014 locka 锁住 obj1
mon mar 31 10:57:08 cst 2014lockb 锁 obj1 失败
mon mar 31 10:57:08 cst 2014locka 锁 obj2 失败
mon mar 31 10:57:09 cst 2014 locka 锁住 obj1
mon mar 31 10:57:09 cst 2014 locka 锁住 obj2

第一次两个线程获取信号量时都会失败,因为失败后b等待时间长,所以a再次尝试时会成功。

实际中,你执行任务内容不同,所需时间是不同的。另外不同的线程,对于获取信号量失败的处理也可能是不同的。所以,虽然不会产生死锁,但是你要根据实际情况,来编写获取失败后的处理机制。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网