JDK锁那些事

为什么需要锁?
(1)多任务环境中才需要;
(2)任务都需要对同一共享资源进行写操作;
(3)对资源的访问是互斥的;

锁有哪些生命周期?
(1)任务通过竞争获取锁才能对该资源进行操作(竞争锁);
(2)当有一个任务在对资源进行更新时(占有锁);
(3)其他任务都不可以对这个资源进行操作(任务阻塞);
(4)直到该任务完成更新(释放锁);
 

模拟场景(卖100张火车票)

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

//线程类模拟一个窗口卖100张火车票,四个窗口同时卖
//线程在java中时使用Runnable接口实现的
public class TicketTest implements Runnable{
	
	private int count = 100;
	//此变量在jvm内存模型的堆区域,在堆里面意味着它是共享资源,每个线程都可以对它进行读写操作
	//会衍生两个问题,可见性与操作原子性,详情查看jvm内存模型原理
	//线程安全最大的表征是在多线程环境下运行,每次运行结果不一样,与预期结果不同
	//private static int count = 100;//静态变量在方法区
	
	private Lock lock = new ReentrantLock();
	//java所有的并发编程以及多线程的知识都在此juc包里面
	
	public static void main(String[] args) {	
		TicketTest t = new TicketTest();
		//四个线程对应四个窗口
		Thread t1 = new Thread(t,"窗口A");
		Thread t2 = new Thread(t,"窗口B");
		Thread t3 = new Thread(t,"窗口C");
		Thread t4 = new Thread(t,"窗口D");
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}
	
	public void run() {
		while(count > 0) {
			
//			//不用锁的情况,会出现重卖问题,应避免超卖,重卖
//			if(count > 0) {//双重校验
//				System.out.println(Thread.currentThread().getName()+
//						"售出第"+
//						count+
//						"张火车票");
//				count--;
//			}
//			try {
//				Thread.sleep(50);//睡眠50毫秒
//			} catch (Exception e) {
//				// TODO: handle exception
//			}

			
//			//方法一,上锁,使用“同步代码块“使线程间同步,不然会出现线程不安全的问题
//			synchronized(this){
//				if(count > 0) {//双重校验
//					System.out.println(Thread.currentThread().getName()+
//							"售出第"+
//							count+
//							"张火车票");
//					count--;
//				}
//			}
//			try {
//				Thread.sleep(50);//睡眠50毫秒
//			} catch (Exception e) {
//				// TODO: handle exception
//			}
			
			
//			//方法二,使用同步函数synchronized
//			sale();
//			try {
//				Thread.sleep(50);//睡眠50毫秒
//			} catch (Exception e) {
//				// TODO: handle exception
//			}
			
			
			//方法三,使用juc包lock
			//lock与synchronized大同小异,需要查看jdk源码,lock比较灵活
			lock.lock();//加锁之后,以下的业务代码就是单线程环境运行,如4个线程竞争这把锁
			try {
				if(count > 0) {//双重校验
					System.out.println(Thread.currentThread().getName()+
							"售出第"+
							count+
							"张火车票");
					count--;
				}
			} catch (Exception e) {
				// TODO: handle exception
			} finally {
				lock.unlock();//解锁,最重要原因为避免死锁,无论正确、异常执行,都执行解锁
			}
			try {
				Thread.sleep(50);//睡眠50毫秒
			} catch (Exception e) {
				// TODO: handle exception
			}
		}
		
	}
	
	
//	//方法二,使用同步函数synchronized
//	public synchronized void sale(){ //使用同步函数使线程间同步
//		if(count > 0) {//双重校验
//			System.out.println(Thread.currentThread().getName()+
//					"售出第"+
//					count+
//					"张火车票");
//			count--;
//		}
//	}
	
	
	/****但是以上三种方法,缺点:jvm锁解决不了分布式环境多任务对共享资源竞争的协同操作问题****/
}

猜你喜欢

转载自blog.csdn.net/Cai181191/article/details/100178724