虽然 synchronized 关键字可以保证 single thread execution,但是如果使用不当就会导致发生死锁,比如 A 手持刀等待 B 放下叉,而 B 手持叉等待 A 放下刀。
下看看下面死锁代码。
package concurrent.eatnoodle;
/**
* @className: Tableware
* @description: 餐具类
* @date: 2022/4/14
* @author: cakin
*/
public class Tableware {
// 餐具名称
private final String toolName;
public Tableware(String toolName) {
this.toolName = toolName;
}
@Override
public String toString() {
return "Tool:" + toolName;
}
}
package concurrent.eatnoodle;
public class EatNoodleThread extends Thread {
private final String name;
// 左手边的餐具
private final Tableware leftTool;
// 右手边的餐具
private final Tableware rightTool;
public EatNoodleThread(String name, Tableware leftTool, Tableware rightTool) {
this.name = name;
this.leftTool = leftTool;
this.rightTool = rightTool;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
this.eat();
}
}
private void eat() {
synchronized (leftTool) {
System.out.println(name + " take up " + leftTool + "(left)");
synchronized (rightTool) {
System.out.println(name + " take up " + rightTool + "(right)");
System.out.println(name + " is eating now.");
System.out.println(name + " put down " + rightTool + "(right)");
}
System.out.println(name + " put down " + leftTool + "(left)");
}
}
}
package concurrent.eatnoodle;
public class Test1 {
public static void main(String[] args) {
Tableware fork = new Tableware("fork");
Tableware knife = new Tableware("knife");
new EatNoodleThread("A", fork, knife).start();
new EatNoodleThread("B", knife, fork).start();
}
}
package concurrent.eatnoodle;
public class TablewarePair {
private final Tableware leftTool;
private final Tableware rightTool;
public TablewarePair(Tableware leftTool, Tableware rightTool) {
this.leftTool = leftTool;
this.rightTool = rightTool;
}
public Tableware getLeftTool() {
return leftTool;
}
public Tableware getRightTool() {
return rightTool;
}
}
package concurrent.eatnoodle;
public class EatNoodleThread1 extends Thread {
private final String name;
private final TablewarePair tablewarePair;
public EatNoodleThread1(String name, TablewarePair tablewarePair) {
this.name = name;
this.tablewarePair = tablewarePair;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
this.eat();
}
}
private void eat() {
synchronized (tablewarePair) {
System.out.println(name + " take up " + tablewarePair.getLeftTool() + "(left)");
System.out.println(name + " take up " + tablewarePair.getRightTool() + "(right)");
System.out.println(name + " is eating now.");
System.out.println(name + " put down " + tablewarePair.getRightTool() + "(right)");
System.out.println(name + " put down " + tablewarePair.getLeftTool() + "(left)");
}
}
}
package concurrent.eatnoodle;
public class Test2 {
public static void main(String[] args) {
Tableware fork = new Tableware("fork");
Tableware knife = new Tableware("knife");
TablewarePair tablewarePair = new TablewarePair(fork, knife);
new EatNoodleThread1("A", tablewarePair).start();
new EatNoodleThread1("B", tablewarePair).start();
}
}
不发生死锁,正常运行。
在 Single Thread Execute 中,synchronized 关键字起到决定性的作用,但是 synchronized 的排他性是以性能的牺牲为代价的,因此在保证线程安全的前提下应尽量缩小 synchronized 的作用域。
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/chengqiuming/article/details/124178940
内容来源于网络,如有侵权,请联系作者删除!