死锁
资源一定是多于1个,同时小于等于竞争的线程数,资源只有一个,只会产生激烈的竞争。
死锁的根本成因:获取锁的顺序不一致导致。
死锁的一般情况:
package com.caojiulu;
import com.caojiulu.SleepTools;
/**
*@author caojiulu
*
*类说明:演示普通的死锁和解决
*/
public class NormalDeadLock {
private static Object valueFirst = new Object();//第一个锁
private static Object valueSecond = new Object();//第二个锁
//先拿第一个锁,再拿第二个锁
private static void fisrtToSecond() throws InterruptedException {
String threadName = Thread.currentThread().getName();
synchronized (valueFirst) {
System.out.println(threadName+" get first");
SleepTools.ms(100);
synchronized (valueSecond) {
System.out.println(threadName+" get second");
}
}
}
//先拿第二个锁,再拿第一个锁
private static void SecondToFisrt() throws InterruptedException {
String threadName = Thread.currentThread().getName();
synchronized (valueSecond) {
System.out.println(threadName+" get first");
SleepTools.ms(100);
synchronized (valueFirst) {
System.out.println(threadName+" get second");
}
}
}
//执行先拿第二个锁,再拿第一个锁
private static class TestThread extends Thread{
private String name;
public TestThread(String name) {
this.name = name;
}
public void run(){
Thread.currentThread().setName(name);
try {
SecondToFisrt();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Thread.currentThread().setName("TestDeadLock");
TestThread testThread = new TestThread("SubTestThread");
testThread.start();
try {
fisrtToSecond();//先拿第一个锁,再拿第二个锁
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
如果在应用程序中,怀疑产生了死锁
通过jps 查询应用的 id,
再通过jstack id 查看应用的锁的持有情况
动态的
动态顺序死锁,在实现时按照某种顺序加锁了,但是因为外部调用的问题,导致无法保证加锁顺序而产生的。
解决:
- 通过内在排序,保证加锁的顺序性,可以通过System.identityHashCode(from);获取原始的hashcode
package com.caojiulu;
/**
*@author caojiulu
*
*类说明:
*/
public class SafeOperate implements ITransfer {
private static Object tieLock = new Object();//加时赛锁
@Override
public void transfer(UserAccount from, UserAccount to, int amount)
throws InterruptedException {
int fromHash = System.identityHashCode(from);
int toHash = System.identityHashCode(to);
//先锁hash小的那个
if(fromHash<toHash) {
synchronized (from){
System.out.println(Thread.currentThread().getName()
+" get"+from.getName());
Thread.sleep(100);
synchronized (to){
System.out.println(Thread.currentThread().getName()
+" get"+to.getName());
from.flyMoney(amount);
to.addMoney(amount);
}
}
}else if(toHash<fromHash) {
synchronized (to){
System.out.println(Thread.currentThread().getName()
+" get"+to.getName());
Thread.sleep(100);
synchronized (from){
System.out.println(Thread.currentThread().getName()
+" get"+from.getName());
from.flyMoney(amount);
to.addMoney(amount);
}
}
}else {//解决hash冲突的方法
synchronized (tieLock) {
synchronized (from) {
synchronized (to) {
from.flyMoney(amount);
to.addMoney(amount);
}
}
}
}
}
}
2. 通过尝试拿锁。
package com.caojiulu;
import java.util.Random;
/**
*@author caojiulu
*
*类说明:不会产生死锁的安全转账第二种方法,尝试拿锁
*/
public class SafeOperateToo implements ITransfer {
@Override
public void transfer(UserAccount from, UserAccount to, int amount)
throws InterruptedException {
Random r = new Random();
while(true) {
if(from.getLock().tryLock()) {
try {
System.out.println(Thread.currentThread().getName()
+" get "+from.getName());
if(to.getLock().tryLock()) {
try {
System.out.println(Thread.currentThread().getName()
+" get "+to.getName());
//两把锁都拿到了
from.flyMoney(amount);
to.addMoney(amount);
break;
}finally {
to.getLock().unlock();
}
}
}finally {
from.getLock().unlock();
}
}
SleepTools.ms(r.nextInt(10));
}
}
}
标签:java,synchronized,Thread,get,getName,System,并发,死锁,println From: https://blog.51cto.com/u_14906615/5899412