Java多线程售票问题

1、代码

public class Test {

	public static void main(String[] args) {
		
		Tickets tickets = new Tickets(10);
		new Thread(tickets, "售票员A").start();
		new Thread(tickets, "售票员B").start();
		new Thread(tickets, "售票员C").start();
	}
}
class Tickets implements Runnable {

	private int num;
	
	Tickets(int num) {
		
		this.num = num;
	}
	
	public void run() {
		
		while(num > 0) {
			
			sale();
		}
	}
	
	private synchronized void sale() {
		
        if(num > 0){  
        	
        	System.out.println(Thread.currentThread().getName() + "卖出一张火车票,还剩余"+ (--num) + "张票。");
        	try{  
                Thread.sleep(100);  
            }catch(InterruptedException e){  
                e.printStackTrace();  
            }  
        }  
    }  
}

2、运行结果

售票员A卖出一张火车票,还剩余9张票。
售票员A卖出一张火车票,还剩余8张票。
售票员B卖出一张火车票,还剩余7张票。
售票员C卖出一张火车票,还剩余6张票。
售票员C卖出一张火车票,还剩余5张票。
售票员B卖出一张火车票,还剩余4张票。
售票员B卖出一张火车票,还剩余3张票。
售票员A卖出一张火车票,还剩余2张票。
售票员A卖出一张火车票,还剩余1张票。
售票员A卖出一张火车票,还剩余0张票。
### Java多线程售票场景下的同步机制实现方式 在Java多线程售票系统中,同步机制的实现是为了确保多个线程对共享资源(如票数)的操作是安全且互斥的。以下是几种常见的实现方式: #### 1. 使用`synchronized`关键字对实例方法加锁 通过将售票逻辑封装在`synchronized`修饰的实例方法中,可以确保同一时刻只有一个线程能够执行该方法。这种方式使用对象本身作为锁。 ```java public class TicketShop implements Runnable { private int num = 100; @Override public void run() { String t = Thread.currentThread().getName(); while (true) { try { Thread.sleep(500); } catch (Exception e) { e.printStackTrace(); } synchronized (this) { // 使用当前对象作为锁 if (num < 1) break; System.out.printf("%s:售出一张票(座号:%d),剩余%d张票%n", t, num, --num); try { Thread.sleep(1000); } catch (Exception e) { e.printStackTrace(); } } } System.out.printf("%s:线程结束(票卖完了)%n", t); } } ``` 此代码片段展示了如何通过`synchronized`关键字对实例方法加锁[^1]。 #### 2. 使用`synchronized`关键字对静态方法加锁 当多个线程需要共享同一个锁时,可以使用静态方法上的`synchronized`关键字。这种方式使用类的`Class`对象作为锁。 ```java public class Ticket { private static int tickets = 100; public static synchronized void sell() { if (tickets > 0) { System.out.println(Thread.currentThread().getName() + " sold ticket " + tickets--); } } } ``` 在此示例中,所有线程共享同一个锁(即`Ticket.class`),从而确保全局互斥[^2]。 #### 3. 使用显式的锁对象 除了依赖`synchronized`关键字外,还可以通过创建一个专门的锁对象来控制线程间的同步。 ```java class Counter3 { private static final Object lock = new Object(); // 显式定义锁对象 public static int count = 0; public static void add() { synchronized (lock) { // 使用显式锁对象 for (int i = 0; i < 100; i++) { Counter3.count += 1; } } } public static void dec() { synchronized (lock) { // 使用显式锁对象 for (int i = 0; i < 100; i++) { Counter3.count -= 1; } } } } ``` 显式锁对象的方式提供了更大的灵活性,并且避免了直接使用类或实例作为锁可能带来的问题[^3]。 #### 4. 使用`ReentrantLock`类 `ReentrantLock`提供了比`synchronized`更强大的功能,例如支持公平锁、可中断锁等。 ```java import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class TicketShop { private int num = 100; private final Lock lock = new ReentrantLock(); // 创建锁对象 public void sellTicket() { lock.lock(); // 加锁 try { if (num > 0) { System.out.println(Thread.currentThread().getName() + " sold ticket " + num--); } } finally { lock.unlock(); // 确保释放锁 } } } ``` `ReentrantLock`允许更细粒度的控制,并且在某些场景下性能优于`synchronized`[^4]。 ### 总结 Java多线程售票场景下的同步机制可以通过多种方式实现,包括使用`synchronized`关键字对实例方法或静态方法加锁、使用显式的锁对象以及使用`ReentrantLock`类。每种方式都有其适用场景和优缺点。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值