线程安全-锁机制 synchronized用法同步方法

一个简单的例子,10个人抢8张票,结果肯定是有2个人抢不到票的

public class Ticket {
	private static CountDownLatch  ctl =new  CountDownLatch(1);
	private ReentrantLock rentLock=new ReentrantLock();
	
	Integer stock=8;//总票数
	
	public  void reduce(int num){
		if((stock-num)>=0){
			
			try {
				ctl.await();//模拟并发场景,相当于所用线程同时到达才会执行
			} catch (Exception e) {
				e.printStackTrace();
			}
			stock-=num;
			System.out.println(Thread.currentThread().getName()+
				"成功卖出:"+num+"张,库存剩余:"+stock+"张");
		}else {
			System.out.println(Thread.currentThread().getName()+
					"失败,库存不足:"+num+"张,库存剩余:"+stock+"张");
		}
	}
	

	
	public static void main(String[] args) throws InterruptedException {
		final Ticket ticket=new Ticket();
		
		for (int i = 0; i <10; i++) {
			new Thread(new Runnable() {
				public void run() {
					ticket.reduce(1); #只有10个线程同时开启时,才会执行该方法,因为reduce方法中调用了ctl.await方法
					//ticket.reduceByLock(1);
				}
			}).start();;
		}
		Thread.sleep(1000);
		ctl.countDown();  //启动一个线程,计数器减一
	}
	
}

运行结果:
线程安全-锁机制 synchronized用法同步方法
出现的负数,这就是线程安全引起的,只要把Ticket 中的reduce 方法加上synchronized 修饰,就可以解决这个问题

一 同步方法 方法加用 synchronized 修饰

public synchronized void reduce(int num){
		if((stock-num)>=0){
			
			try {
				ctl.await();//模拟并发场景,相当于所用线程同时到达才会执行
			} catch (Exception e) {
				e.printStackTrace();
			}
			stock-=num;
			System.out.println(Thread.currentThread().getName()+
				"成功卖出:"+num+"张,库存剩余:"+stock+"张");
		}else {
			System.out.println(Thread.currentThread().getName()+
					"失败,库存不足:"+num+"张,库存剩余:"+stock+"张");
		}
	}

再次运行结果:
线程安全-锁机制 synchronized用法同步方法

为什么呢,因为加了synchronized 关键字后,会保证每次只会用一个线程去调用reduce这个方法,当一个线程1在执行这个方法的时候,会获得锁,其他线程阻塞等待,线程1执行完之后,释放锁,其他线程竞争锁。得到锁的线程执行reduce方法,其他线程阻塞等待,以此类推,直到10个线程都执行完

加在方法上的锁(也叫同步方法),锁的都是对象,例子中执行时锁的就是这个 ticket 对象(也就是调用reduce这个方法的对象)
线程安全-锁机制 synchronized用法同步方法

同步方法的缺点:因为锁在方法上,导致了锁的范围过大,会使单个线程串行执行时间变长,其他线程等待时间变长;影响系统性能