Java线程同步 线程死锁

  

 

解决超卖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package ersatz.thread;
 
public class T {
  public static void main(String[] args) {
    Ticket ticket = new Ticket();
    new Thread(ticket).start();
    new Thread(ticket).start();
    new Thread(ticket).start();
  }
}
 
class Ticket implements Runnable {
  private int number = 50;
  private boolean loop = true;
  Object o = new Object();
 
  // 同步方法(static)的锁为当前类
//  public synchronized static void m(){} 锁加在Ticket.class
//  静态方法中,实现一个同步代码块
//  synchronized (Ticket.class) {
//
//  }
  public static void m() {
    synchronized (Ticket.class) {
      System.out.println();
    }
  }
 
  //  public synchronized void m(){}是一个同步方法,锁在this,可在代码块写synchronized,同步代码块,互斥锁还是在this
  public /*synchronized*/ void sell() {  // 同步方法,在同一时刻,只能有一个线程来执行sell方法
    synchronized (/*this*/ o) {
      if (number <= 0) {
        System.out.println("ticket out of number");
        loop = false;
        return;
      }
      try {
        Thread.sleep(50);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      System.out.println(Thread.currentThread().getName() + " sell ticket " + "left: " + --number);
    }
  }
 
  @Override
  public void run() {
    while (loop) sell();
  }
}

  

 

以下代码不能解决超卖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package ersatz.thread;
 
public class T {
  public static void main(String[] args) {
    Ticket ticket1 = new Ticket();
    Ticket ticket2 = new Ticket();
    Ticket ticket3 = new Ticket();
    ticket1.start();
    ticket2.start();
    ticket3.start();
  }
}
 
class Ticket extends Thread {
  private static int number = 50;
  private boolean loop = true;
 
  public void sell() {
    synchronized (this) {
      if (number <= 0) {
        System.out.println("ticket out of number");
        loop = false;
        return;
      }
      try {
        Thread.sleep(50);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      System.out.println(Thread.currentThread().getName() + " sell ticket: " + number + ", left: " + --number);
    }
  }
 
  @Override
  public void run() {
    while (loop) sell();
  }
}

  

 

 

 

 

 

 

Deadlock

复制代码
package ersatz.thread;

public class T {
  public static void main(String[] args) {
    Deadlock d1 = new Deadlock(true);
    Deadlock d2 = new Deadlock(false);
    d1.setName("Thread-A");
    d2.setName("Thread-B");
    d1.start();
    d2.start();
  }
}

class Deadlock extends Thread {
  protected static final Object o1 = new Object();  // 保证多线程共享同一对象
  protected static final Object o2 = new Object();
  protected boolean flag;

  public Deadlock(boolean flag) {
    this.flag = flag;
  }

  @Override
  public void run() {
    //1. 如果flag 为 T, 线程A 就会先得到/持有 o1 对象锁, 然后尝试去获取 o2 对象锁
    //2. 如果线程A 得不到 o2 对象锁,就会Blocked
    //3. 如果flag 为 F, 线程B 就会先得到/持有 o2 对象锁, 然后尝试去获取 o1 对象锁
    //4. 如果线程B 得不到 o1 对象锁,就会Blocked
    if (flag) {
      synchronized (o1) {  // 对象互斥锁,下面为同步代码
        System.out.println(Thread.currentThread().getName() + " obtain o1 lock");
        synchronized (o2) {
          System.out.println(Thread.currentThread().getName() + " obtain o2 lock");
        }
      }
    } else {
      synchronized (o2) {
        System.out.println(Thread.currentThread().getName() + " obtain o2 lock");
        synchronized (o1) {
          System.out.println(Thread.currentThread().getName() + " obtain o1 lock");
        }
      }
    }
  }
}
复制代码

 

 

 

 

 

释放锁:

 

 

下列操作不会释放锁

 

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package ersatz.thread;
 
import java.util.Scanner;
 
public class T {
  public static void main(String[] args) {
    A a = new A();
    B b = new B(a);
    a.setName("Thread-A");
    b.setName("Thread-B");
    a.start();
    b.start();
  }
}
 
class A extends Thread {
  private boolean loop = true;
 
  public void setLoop(boolean loop) {
    this.loop = loop;
  }
 
  @Override
  public void run() {
    while (loop) {
      System.out.println((int) (Math.random() * 100 + 1));
      try {
        Thread.sleep(1000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
    System.out.println(Thread.currentThread().getName() + " exit");
  }
}
 
class B extends Thread {
  private A a = null;
  private final Scanner scanner = new Scanner(System.in);
 
  public B(A a) {
    this.a = a;
  }
 
  @Override
  public void run() {
    while (true) {
      System.out.println("input Q to exit:");
      char key = scanner.next().toUpperCase().charAt(0);
      if (key == 'Q') {
        a.setLoop(false);
        System.out.println(Thread.currentThread().getName() + " exit");
        break;
      }
    }
  }
}

  

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package ersatz.thread;
public class T {
  public static void main(String[] args) {
    B b = new B();
    Thread t1 = new Thread(b);
    t1.setName("Thread-A");
    Thread t2 = new Thread(b);
    t2.setName("Thread-B");
    t1.start();
    t2.start();
  }
}
class B implements Runnable{
  private int balance=10000;
 
  @Override
  public void run() {
    do {
      synchronized (this) {
        if (balance < 1000) {
          System.out.println("insufficient balance: " + balance+' '+Thread.currentThread().getName()+" exit");
          break;
        }
        System.out.println(Thread.currentThread().getName() + " withdraw 1000, balance: " + (balance -= 1000));
      }
      try {
        Thread.sleep(1000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    } while (true);
  }
}

  

posted @   ascertain  阅读(39)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示