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 ); } } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律