您的位置:首页 > 编程语言 > Java开发

Java线程:并发协作-死锁

2015-06-16 11:10 627 查看


源作者地址:http://www.cnblogs.com/riskyer/p/3263032.html




Java线程:并发协作-死锁

线程发生死锁可能性很小,即使看似可能发生死锁的代码,在运行时发生死锁的可能性也是小之又小。

 

发生死锁的原因一般是两个对象的锁相互等待造成的。

 

在《Java线程:线程的同步与锁》一文中,简述死锁的概念与简单例子,但是所给的例子是不完整的,这里给出一个完整的例子。

/**
* Java线程:并发协作-死锁
*
* @author Administrator 2009-11-4 22:06:13
*/
publicclass Test {
publicstaticvoid main(String[] args) {
DeadlockRisk dead = new DeadlockRisk();
MyThread t1 = new MyThread(dead, 1, 2);
MyThread t2 = new MyThread(dead, 3, 4);
MyThread t3 = new MyThread(dead, 5, 6);
MyThread t4 = new MyThread(dead, 7, 8);

t1.start();
t2.start();
t3.start();
t4.start();
}

}

class MyThread extends Thread {
private DeadlockRisk dead;
privateint a, b;

MyThread(DeadlockRisk dead, int a,int b) {
this.dead = dead;
this.a = a;
this.b = b;
}

@Override
publicvoid run() {
dead.read();
dead.write(a, b);
}
}

class DeadlockRisk {
privatestaticclass Resource {
publicint value;
}

private Resource resourceA =new Resource();
private Resource resourceB =new Resource();

publicint read() {
synchronized (resourceA) {
System.out.println("read():" + Thread.currentThread().getName() +"获取了resourceA的锁!");
synchronized (resourceB) {
System.out.println("read():" + Thread.currentThread().getName() +"获取了resourceB的锁!");
return resourceB.value + resourceA.value;
}
}
}

publicvoid write(int a,int b) {
synchronized (resourceB) {
System.out.println("write():" + Thread.currentThread().getName() +"获取了resourceA的锁!");
synchronized (resourceA) {
System.out.println("write():" + Thread.currentThread().getName() +"获取了resourceB的锁!");
resourceA.value = a;
resourceB.value = b;
}
}
}
}


下面死锁的情况发生了,真是难得一见啊:

 

 

Java线程:volatile关键字

 

Java™ 语言包含两种内在的同步机制:同步块(或方法)和 volatile变量。这两种机制的提出都是为了实现代码线程的安全性。其中 Volatile变量的同步性较差(但有时它更简单并且开销更低),而且其使用也更容易出错。

 

谈及到volatile关键字,不得不提的一篇文章是:《Java理论与实践:正确使用 Volatile 变量》,这篇文章对volatile关键字的用法做了相当精辟的阐述。

 

之所以要单独提出volatile这个不常用的关键字原因是这个关键字在高性能的多线程程序中也有很重要的用途,只是这个关键字用不好会出很多问题。

 

首先考虑一个问题,为什么变量需要volatile来修饰呢?

要搞清楚这个问题,首先应该明白计算机内部都做什么了。比如做了一个i++操作,计算机内部做了三次处理:读取-修改-写入。

同样,对于一个long型数据,做了个赋值操作,在32系统下需要经过两步才能完成,先修改低32位,然后修改高32位。

 

假想一下,当将以上的操作放到一个多线程环境下操作时候,有可能出现的问题,是这些步骤执行了一部分,而另外一个线程就已经引用了变量值,这样就导致了读取脏数据的问题。

 

通过这个设想,就不难理解volatile关键字了。

 

volatile可以用在任何变量前面,但不能用于final变量前面,因为final型的变量是禁止修改的。也不存在线程安全的问题。

 

更多的内容,请参看::《Java理论与实践:正确使用 Volatile 变量》一文,写得很好。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息