修改 使用锁 或者同步机制
仅仅给变量添加volatile 是不行的 还会出现多卖少买状况
synchronized 简介 :非常经典的处理手段,具体使用有多种形式,它的核心思想就是修饰一个方法或者一段代码,这段代码不能同时两个以上的线程同时运行。
代码块 中的this 是调用该方法的对象 一般都是使用代码块
理解一下synchronized 直译过来 是同步的意思 但是我们京城称呼其为一种锁,为什么叫锁,原则上每个对象都可以持有一把锁,当某一个线程操作这个对象时, 这个线程就获得该对象的锁,在此期间其他线程就无法操作该对象了
Lock
简介:Lock是自JDK1.5 之后推出的一个接口,当热也是一系列子实现类,接口非常重要,定义了Java所认定的锁的概念,跟synchronized有显著区别,
synchronized是一个关键字,使用它可以实现类似锁的效果,但是严格的来说它并不是锁,Lock是一个接口,详细描述了锁的概念,其中重点包含若干方法,这些方法就是核心内容了。
方法:
lock():这个方法用来加锁,或者可以理解为获取对象的锁,如果获取成功,就执行下面的代码,若获取失败则一直等待,重复尝试获取
lockInterruptibly(); 也是尝试获取锁,但是对应带了Interrupter这个部分,所以对于获取锁的结果会进行进一步工作;
tryLock(); 尝试获取锁,返回值boolean类型,会返回获取锁的结果,跟lock()不一样,如果获取失败,返回false ,并且不会继续尝试获取;
unlock():解锁,运行之后即可释放锁,就能让其他线程获取了;
ReentrantLock:
是最常用的子实现类,加强对它的熟悉字面翻译它叫重入锁,确实它也是符合重入锁的要求,但是它仅仅可以表示重入锁。
可重入锁:
是一个概念,可重用锁在大部分时候并不直接表示RenntrantLock,可重用锁强调的是一种类型,这个类型关键特点是可重入,什么是可重入?
就是一个已经获得锁的线程还能继续调用加锁的代码。
这里我们强调可重入是一种典型的锁的类型,我们自己可以编码实现一些可重入锁,在实际项目中它的运用可以体现灵活性等等诸多优势点,就不一一展开。
ThreadDemo类
/**
* @Author: Jiangjun
* @Date: 2019/10/7 11:53
* @Description: 描述购票的逻辑
*/
public class ThreadDemo implements Runnable{
Lock lock = new ReentrantLock();
volatile int num = 20;
@Override
public void run() {
lock.lock();
while (num>0){
addlock();
System.out.println(Thread.currentThread().getName() + "认为此时还有票可选");
num = num - 1;
System.out.println(Thread.currentThread().getName() + "买到了一张票,还剩" + num);
}
lock.unlock();
}
public void addlock(){
lock.lock();
}
}
主函数:
public class TestMain {
public static void main(String[] args) {
ThreadDemo td = new ThreadDemo();
Thread t1 = new Thread(td,"掌上编程");
Thread t2 = new Thread(td,"公众号");
t1.start();
t2.start();
}
}
公平锁:
公平=先来后到,先来的获取锁,就来的后获取锁。
同样公平锁也是一种概念,也是一种锁的类型,如果设计锁的机制符合公平要求,那么这个锁就是公平的锁。
若适用购票场景,如果强调先来后到,(从性能角度考虑)就必须采取特备的方案来实现这种先后顺序,这样必然会带来性能损失,所以公平锁的性能会劣于非公平锁。
如果我们使用非公平锁也会带带来一定风险,容易造成真实意义上的不公平,就有一些线程老早就在等待了,但是运气不好一直拿不到锁,这个可以成为锁饥饿现象。
因此我们强调根据情况来选择锁是否公平,一般如果要力避免掉锁饥饿现象,就要考虑使用公平锁,否则可以使用非公平锁。
Synchronized 只能是非公平锁
ReentrantLock 是后来加入的类,所以在设计上更加完善,可以直接通过构造函数来制定锁是否公平。
细节注意:
养成比较规范的编码习惯,一旦使了Lock,要充分考虑到可能出现的报错情况,所以一般编码会这样写try...catch...fianlly
public class LockFairThread implements Runnable{
//创建公平锁
private static ReentrantLock lock = new ReentrantLock(true);
@Override
public void run() {
lock.lock();
try{
System.out.println(Thread.currentThread().getName() + "获得锁");
}catch (Exception e){
System.out.println("异常相关提示");
}finally {
lock.unlock();
}
}
}
原文:https://www.cnblogs.com/mzdljgz/p/11630576.html