死锁代码
最简单死锁情况
public static void main(String[] args) throws InterruptedException {
Object lock1 = new Object();
Object lock2 = new Object();
new Thread(() -> {
synchronized (lock1) {
System.out.println(Thread.currentThread().getName() + "获得了lock1");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock2) {
System.out.println(Thread.currentThread().getName() + "获得了lock2");
}
}
}).start();
new Thread(() -> {
synchronized (lock2) {
System.out.println(Thread.currentThread().getName() + "获得了lock1");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock1) {
System.out.println(Thread.currentThread().getName() + "获得了lock2");
}
}
}).start();
}
银行转账问题
import java.util.Random;
public class Main {
public static void main(String[] args) throws InterruptedException {
//mustDeadLock(); //必然死锁
randomDeadLock(100, 20); //随机死锁
}
public static Account[] initAccount(int count) { //批量账户初始化,每个账户余额在1000到2000之间
Account[] accounts = new Account[count];
Random random = new Random(); //用于生成随机数
for (int i = 0; i < accounts.length; i++) {
accounts[i] = new Account("account" + i, 1000 + random.nextInt(1000));
}
return accounts;
}
public static void randomTransferMoney(Account[] accounts) { //随机转账
Random random = new Random(); //用于生成随机数
for (int i = 0; i < accounts.length; i++) {
int fromAccountIndex = random.nextInt(accounts.length);
int toAccountIndex = random.nextInt(accounts.length);
int amount = 100 + random.nextInt(500); //转账钱数是100到500之间
int time = random.nextInt(1000); //转账延时时间
new TransferMoney(accounts[fromAccountIndex], accounts[toAccountIndex], time).transferMoney(amount);
}
}
public static void mustDeadLock() { //必然死锁的情况
Account accountA = new Account("A", 500);
Account accountB = new Account("B", 500);
new Thread(() ->
new TransferMoney(accountA, accountB, 100).transferMoney(200)
).start();
new Thread(() ->
new TransferMoney(accountB, accountA, 100).transferMoney(200)
).start();
}
public static void randomDeadLock(int accountCount, int threadCount) { //随机死锁的情况
Account[] accounts = initAccount(accountCount); //批量初始化账户开启不同线程进行转账,账户量容易出现死锁
for (int i = 0; i < threadCount; i++) {
new Thread(() -> {
randomTransferMoney(accounts);
}).start();
}
}
}
class Account { //账户类
private String name; //账户名
private int balance; //账户余额
public Account(String name, int balance) {
this.name = name;
this.balance = balance;
}
public void setBalance(int balance) {
this.balance = balance;
}
public int getBalance() {
return balance;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "账户" + name + "的余额为" + balance;
}
}
class TransferMoney {
private Account from; //转出账户
private Account to; //转入账户
private int time; //转账延时时间,单位毫秒,默认0
public TransferMoney(Account from, Account to, int time) {
this.from = from;
this.to = to;
this.time = time;
}
public TransferMoney(Account from, Account to) {
this(from, to, 0);
}
public void transferMoney(int amount) {
synchronized (from) {
int balance = from.getBalance(); //查看余额是否充足
if (balance - amount < 0) {
System.out.println("余额不足,转账失败");
return;
}
if (time > 0) { //设置时间就延时,若设置转账延时就会进入死锁状态
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
synchronized (to) {
from.setBalance(balance - amount); //转账操作
to.setBalance(to.getBalance() + amount);
System.out.println("从" + from.getName() + "到" + to.getName() + ",成功转账" + amount + "元");
}
}
}
}
哲学家就餐问题
问题描述:有五位哲学家围坐在一张圆形餐桌旁,哲学家只能做吃饭或思考这两件事,餐桌中间有饭,每位哲学家之间各有一只筷子,哲学家必须用两只筷子吃东西,并且只能使用自己左右手边的那两只筷子
在不考虑意大利面有多少,也不考虑哲学家的胃有多大,设计一套规则,使得在哲学家们在完全不交谈,也就是无法知道其他人可能在什么时候要吃饭或者思考的情况下,可以在这吃饭思考两种状态下永远交替下去
产生死锁的情况:每个哲学家都拿起左手的筷子,永远等待右边的筷子,反之依然
class Philosopher implements Runnable { //哲学家类
private Object leftChopstick;
private Object rightChopstick;
public Philosopher(Object leftChopstick, Object rightChopstick) {
this.leftChopstick = leftChopstick;
this.rightChopstick = rightChopstick;
}
@Override
public void run() { //哲学家的动作,吃饭或思考
try {
while (true) {
doAction("思考中");
synchronized (leftChopstick) {
doAction("拿起左边的筷子");
synchronized (rightChopstick) {
doAction("拿起右边的筷子 -> 开始进食");
doAction("放下右边的筷子");
}
doAction("放行左边的筷子");
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void doAction(String action) throws InterruptedException { //哲学家所作的动作
System.out.println(Thread.currentThread().getName() + " -> " + action);
Thread.sleep((long) (Math.random() * 10)); //该动作持续随机时间
}
}
public class DiningPhilosophers {
public static Object[] initChopsticks(int count) {
Object[] chopsticks = new Object[count];
for (int i = 0; i < chopsticks.length; i++) { //初始化筷子
chopsticks[i] = new Object();
}
return chopsticks;
}
public static Philosopher[] initPhilosophers(Object[] chopsticks) {
Philosopher[] philosophers = new Philosopher[chopsticks.length];
for (int i = 0; i < philosophers.length; i++) { //初始化哲学家
Object leftChopstick = chopsticks[i];
Object rightChopstick = chopsticks[(i + 1) % chopsticks.length]; //使用取余方式取到哲学家两测的筷子
philosophers[i] = new Philosopher(leftChopstick, rightChopstick);
}
return philosophers;
}
public static void main(String[] args) {
Object[] chopsticks = initChopsticks(5);
Philosopher[] philosophers = initPhilosophers(chopsticks);
for (int i = 0; i < philosophers.length; i++) {
new Thread(philosophers[i], "哲学家" + (i)).start(); //启动哲学家线程
}
}
}
死锁的必要条件
以下四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要一个条件不满足,就不会发生死锁
- 互斥条件:一个资源只能同时被一个进程或线程使用
- 请求与保持条件:一个进程或线程,因请求资源而阻塞时,对已获得的资源保持不放
- 不剥夺条件:进程或线程,已获得的资源,在末使用完之前,不能被外界强行剥夺
- 循环等待条件:若干进程或线程之间,形成一种头尾相接的循环等待资源关系
Comments NOTHING