为什么需要锁?
(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锁解决不了分布式环境多任务对共享资源竞争的协同操作问题****/
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/151191.html