基于synchronized的对象锁,类锁以及死锁模拟

本文通过实例详细讲解了Java中的synchronized关键字使用,包括对象锁、类锁的实现,并通过代码展示了死锁的情况。在对象锁中,不同对象访问不会相互阻塞;类锁则确保同一时刻只有一个线程访问,不同对象访问类锁会产生阻塞。同时,文章通过E和E1类的静态同步方法模拟了死锁,两个线程各自持有对方需要的锁,导致双方都无法继续执行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

分为对象锁和类锁
public class T {

	public void test1() throws Exception{
     synchronized(this){ //对象锁
    	 System.out.println(Thread.currentThread().getName()+"---test1  Doing");
    	 Thread.currentThread().sleep(2000);
    	 test2();
     };
	}
	
	public synchronized void test2() throws Exception{ //同test1方法
	    System.out.println(Thread.currentThread().getName()+"--- test2 Doing");
	    Thread.currentThread().sleep(2000);
	    test1();
	}
	
	public void testclass1() throws Exception{
	     synchronized(T.class){//类锁
	    	 System.out.println(Thread.currentThread().getName()+"---testclass1  Doing");
	    	 Thread.currentThread().sleep(2000);
	    	 
	     };
	}
	
	public static synchronized void testclass2() throws Exception{ //同testclass1方法
    	 System.out.println(Thread.currentThread().getName()+"---testclass2  Doing");
    	 Thread.currentThread().sleep(2000);
    	 testclass3();
	}
	
	public static synchronized void testclass3() throws Exception{ //同testclass1方法
   	  System.out.println(Thread.currentThread().getName()+"---testclass3  Doing");
   	  Thread.currentThread().sleep(2000);
   	  testclass2();
	}
}



不同对象 访问类锁测试:
public class clent {

	public static void main(String[] args) throws Exception {
		final CountDownLatch c=new CountDownLatch(1);
		new Thread(new Runnable(){
			@Override
			public void run() {
				T t1=new T();
				try {
					System.out.println(Thread.currentThread().getName()+"启动");
					c.await();
					t1.testclass3();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}).start();
	   new Thread(new Runnable(){
					@Override
					public void run() {
						T t1=new T();
						try {
							System.out.println(Thread.currentThread().getName()+"启动");
							c.await();
							t1.testclass2();
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				}).start();
	   c.countDown();
	   /* 可以发现 类的synchronized一个线程获得不释放,其他线程就不能访问 通过Jconsole可以看到Thread0 一直在等待Thread1
	   Thread-1启动
	   Thread-1---testclass2  Doing
	   Thread-0启动
	   Thread-1---testclass3  Doing
	   Thread-1---testclass2  Doing
	   Thread-1---testclass2  Doing
	   Thread-1---testclass3  Doing*/
	}


不同对象访问对象锁测试:
public class clent1 {

	public static void main(String[] args) {
		final CountDownLatch c=new CountDownLatch(1);
		new Thread(new Runnable(){
			@Override
			public void run() {
				T t1=new T();
				try {
					System.out.println(Thread.currentThread().getName()+"启动");
					c.await();
					t1.test1();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}).start();
	   new Thread(new Runnable(){
					@Override
					public void run() {
						T t1=new T();
						try {
							System.out.println(Thread.currentThread().getName()+"启动");
							c.await();
							t1.test2();
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				}).start();
	   c.countDown();
	  /* Thread-0启动
	   Thread-0---test1  Doing
	   Thread-1启动
	   Thread-1--- test2 Doing
      */
	}



同一个对象,多个线程访问对象锁测试:
public class client2 {
	public static void main(String[] args) {
		final CountDownLatch c=new CountDownLatch(1);
		final T t1=new T();
		new Thread(new Runnable(){
			@Override
			public void run() {
				
				try {
					System.out.println(Thread.currentThread().getName()+"启动");
					c.await();
					t1.test1();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}).start();
	   new Thread(new Runnable(){
					@Override
					public void run() {
						
						try {
							System.out.println(Thread.currentThread().getName()+"启动");
							c.await();
							t1.test2();
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				}).start();
	   c.countDown();
	}
	
	/*结果 同一个对象,当其中一个线程没有释放锁时,另一个会一直等待。
	Thread-1启动
	Thread-1--- test2 Doing
	Thread-0启动
	Thread-1---test1  Doing
	Thread-1--- test2 Doing
	Thread-1---test1  Doing
	Thread-1--- test2 Doing*/

}


以上演示的是阻塞等待,下面演示死锁。
public class E {
	public static synchronized void testclass() throws Exception{ 
   	 System.out.println(Thread.currentThread().getName()+"---E.method  Doing");
   	 Thread.currentThread().sleep(2000);
   	 E1.testclass();
	}
}


public class E1 {
	public static synchronized void testclass() throws Exception{ 
	   	 System.out.println(Thread.currentThread().getName()+"---E1.method  Doing");
	   	Thread.currentThread().sleep(1000);
	   	 E.testclass();
		}
}
public class SiSuo {

	public static void main(String[] args) {
		final CountDownLatch c=new CountDownLatch(1);
		new Thread(new Runnable(){
			@Override
			public void run() {
				try {
					c.await();
					E.testclass();
					E1.testclass();
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			
		}).start();
		
		new Thread(new Runnable(){
			@Override
			public void run() {
				try {
					c.await();
					E1.testclass();
					E.testclass();
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			
		}).start();
		c.countDown();
	}
	/*执行结果,一直等待
	Thread-1---E1.method  Doing
	Thread-0---E.method  Doing*/

}




<think>嗯,用户想要找Java中使用悲观实现库存数量限制的示例代码。首先,我需要回忆一下悲观的相关知识。悲观通常假设并发冲突很可能会发生,因此在访问数据前会先加,确保同一时间只有一个线程可以操作数据。Java中常用的悲观实现方式有synchronized关键字和ReentrantLock。 根据用户提供的引用内容,特别是引用[1]、[2]、[3],里面提到了使用ReentrantLock和synchronized来实现悲观。例如,引用[1]提到同步代码块使用synchronized,而ReentrantLock则是通过对象管理。引用[2]提到两者都是可重入,有助于避免死锁。引用[3]中也有使用ReentrantLock的示例。 用户需要库存数量限制的代码,所以可能需要一个共享的库存变量,然后在减库存的操作前加。我应该考虑线程安全的问题,确保多个线程同时操作库存时不会出现超卖。 首先,使用synchronized的方式比较简单,可以用同步方法或同步代码块。例如,在减库存的方法前加上synchronized关键字,或者用synchronized(this)包围代码块。这样可以保证同一时间只有一个线程执行该方法或代码块。 其次,使用ReentrantLock的方式需要显式地加和解。通常会在try-finally块中确保的释放,防止异常导致无法释放。引用[1]和[3]中的示例应该可以参考,比如创建ReentrantLock实例,在操作前lock(),操作后unlock()。 还要注意库存数量的检查,比如库存是否大于0,然后再减少库存。这两个操作必须原子化,否则可能出现竞态条件。比如,检查库存后,在减少库存前,另一个线程可能已经修改了库存,导致超卖。 所以示例代码中需要将检查和减库存的操作放在的范围内。比如,在定之后,先检查库存是否足够,如果足够则减少库存,否则返回失败。 然后,用户可能还需要比较两种方式的优缺点,比如synchronized是关键字,使用简单,而ReentrantLock更灵活,支持尝试获取、超时等。引用[2]提到两者都是可重入的,有助于避免死锁。 还需要考虑异常处理,确保在发生异常时能被正确释放,避免死锁。对于ReentrantLock,必须在finally块中调用unlock(),这点很重要。 现在,根据这些思考,我需要组织两个示例代码,一个是使用synchronized的,另一个是使用ReentrantLock的。每个示例都需要一个库存,包含库存数量和方法来减少库存,并在方法中使用悲观来保证线程安全。 同时,需要说明这两种方法的适用场景,比如高并发下的性能差异,以及如何选择。可能引用[1]中的内容提到性能对比,冲突概率的影响,所以在高冲突情况下,悲观可能更适合。 最后,生成相关问题,帮助用户进一步理解悲观的应用和优化,比如如何选择型,性能优化的方法,或者与其他机制的对比。</think>### Java中使用悲观实现库存数量限制的示例代码 以下是两种实现方式(基于 `synchronized` 和 `ReentrantLock`),均用于限制库存数量并发修改。 --- #### **方式1:使用 `synchronized` 关键字** ```java public class InventorySynchronized { private int stock = 100; // 初始库存 // 减库存操作(同步方法) public synchronized boolean reduceStock(int quantity) { if (stock >= quantity) { stock -= quantity; return true; } return false; } // 测试代码 public static void main(String[] args) { InventorySynchronized inventory = new InventorySynchronized(); // 模拟10个线程并发减库存 for (int i = 0; i < 10; i++) { new Thread(() -> { boolean result = inventory.reduceStock(10); System.out.println("扣减结果:" + result); }).start(); } } } ``` **说明** - `synchronized` 修饰方法,确保同一时间只有一个线程执行减库存操作[^1]。 - 检查和修改库存的原子性通过保证,避免超卖问题。 --- #### **方式2:使用 `ReentrantLock`** ```java import java.util.concurrent.locks.ReentrantLock; public class InventoryReentrantLock { private int stock = 100; // 初始库存 private final ReentrantLock lock = new ReentrantLock(); // 减库存操作 public boolean reduceStock(int quantity) { lock.lock(); // 显式加 try { if (stock >= quantity) { stock -= quantity; return true; } return false; } finally { lock.unlock(); // 确保释放 } } // 测试代码(同方式1) public static void main(String[] args) { InventoryReentrantLock inventory = new InventoryReentrantLock(); for (int i = 0; i < 10; i++) { new Thread(() -> { boolean result = inventory.reduceStock(10); System.out.println("扣减结果:" + result); }).start(); } } } ``` **说明** - `ReentrantLock` 通过显式加和解控制临界区[^3]。 - `finally` 块确保必然释放,避免死锁[^2]。 --- ### **两种方式的对比** | 特性 | `synchronized` | `ReentrantLock` | |--------------------|-----------------------------------------|------------------------------------------| | 获取方式 | 隐式(JVM管理) | 显式(代码控制) | | 可中断性 | 不支持 | 支持(`lockInterruptibly()`) | | 公平 | 非公平 | 可配置公平性 | | 适用场景 | 简单同步需求 | 复杂并发控制(如超时、条件变量) | --- ### **注意事项** 1. **粒度**:应尽量缩小范围以提高性能。 2. **死锁风险**:避免嵌套或未释放的操作。 3. **性能优化**:高并发场景下,`ReentrantLock` 可通过非阻塞尝试(如 `tryLock()`)减少线程等待[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值