Atomic+Volatile实现买票安全

我们直接上例子,用atomic保证变量的原子性,用volatile保证变量的可见性与有序性, 至此并发的三大特性都被有效的解决了,故而就不会存在线程安全问题了

public class SelltickrtDemo {

    public static void main(String[] args) {

        SellTicket sellTicket = new SellTicket();

        Thread thread1 = new Thread(sellTicket, "窗口1");
        Thread thread2 = new Thread(sellTicket, "窗口2");
        Thread thread3 = new Thread(sellTicket, "窗口3");


        thread1.start();
        thread2.start();
        thread3.start();
    }
}

import java.util.concurrent.atomic.AtomicInteger;

public class SellTicket implements Runnable {

    private volatile AtomicInteger ticket = new AtomicInteger(100);

    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (ticket.get() > 0) {
                System.out.println(Thread.currentThread().getName() + "正在出售第" + ticket.getAndDecrement() + "张票");
            }
        }
    }
}

窗口3正在出售第99张票
窗口1正在出售第98张票
窗口2正在出售第100张票
窗口2正在出售第97张票
窗口3正在出售第95张票
窗口1正在出售第96张票
窗口2正在出售第94张票
窗口3正在出售第93张票
窗口1正在出售第92张票
窗口2正在出售第91张票
窗口1正在出售第90张票
窗口3正在出售第89张票
窗口2正在出售第88张票
窗口3正在出售第87张票
窗口1正在出售第86张票
窗口1正在出售第85张票
窗口3正在出售第84张票
窗口2正在出售第83张票
窗口3正在出售第82张票
窗口2正在出售第81张票
窗口1正在出售第80张票
窗口2正在出售第79张票
窗口3正在出售第78张票
窗口1正在出售第77张票
窗口1正在出售第76张票
窗口2正在出售第75张票
窗口3正在出售第74张票
窗口2正在出售第72张票
窗口3正在出售第71张票
窗口1正在出售第73张票
窗口3正在出售第69张票
窗口2正在出售第68张票
窗口1正在出售第70张票
窗口3正在出售第67张票
窗口2正在出售第65张票
窗口1正在出售第66张票
窗口3正在出售第64张票
窗口1正在出售第63张票
窗口2正在出售第62张票
窗口3正在出售第61张票
窗口1正在出售第60张票
窗口2正在出售第59张票
窗口1正在出售第57张票
窗口3正在出售第58张票
窗口2正在出售第56张票
窗口1正在出售第55张票
窗口2正在出售第54张票
窗口3正在出售第53张票
窗口3正在出售第52张票
窗口2正在出售第51张票
窗口1正在出售第50张票
窗口2正在出售第49张票
窗口1正在出售第47张票
窗口3正在出售第48张票
窗口3正在出售第46张票
窗口1正在出售第45张票
窗口2正在出售第44张票
窗口2正在出售第43张票
窗口1正在出售第42张票
窗口3正在出售第41张票
窗口1正在出售第39张票
窗口3正在出售第38张票
窗口2正在出售第40张票
窗口2正在出售第37张票
窗口3正在出售第36张票
窗口1正在出售第35张票
窗口1正在出售第33张票
窗口3正在出售第32张票
窗口2正在出售第34张票
窗口2正在出售第31张票
窗口3正在出售第30张票
窗口1正在出售第29张票
窗口3正在出售第28张票
窗口2正在出售第26张票
窗口1正在出售第27张票
窗口1正在出售第24张票
窗口2正在出售第23张票
窗口3正在出售第25张票
窗口1正在出售第22张票
窗口3正在出售第21张票
窗口2正在出售第20张票
窗口2正在出售第19张票
窗口1正在出售第18张票
窗口3正在出售第17张票
窗口2正在出售第15张票
窗口1正在出售第16张票
窗口3正在出售第14张票
窗口1正在出售第13张票
窗口3正在出售第12张票
窗口2正在出售第11张票
窗口2正在出售第10张票
窗口3正在出售第9张票
窗口1正在出售第8张票
窗口3正在出售第6张票
窗口2正在出售第5张票
窗口1正在出售第7张票
窗口3正在出售第4张票
窗口1正在出售第3张票
窗口2正在出售第2张票
窗口2正在出售第1张票

接下来我们看看synchronized 锁,其实在JDK的源码中,JVM的底层维护了两个底层命令lock和unlock用来加锁和释放锁,对 对象头 进行加锁(实际上也就是C++层面的锁,即在C++层面用阻塞队列将线程阻塞),运行下面这段代码就会发现上面的时间需要少些,而synchronized是按100规规矩矩减到1,从一定程度上遏制了“并发”,锁的粒度要大于CAS锁机制

为什么这么说了?因为CAS底层是通过CPU硬件级别的原语指令保障的,即cmpxchg保证的,执行cmpxchg指令的时候,会判断当前系统是否是多核系统,如果是就给总线加锁,只有一个线程会对总线加锁成功,加锁成功之后会执行CAS操作,也即是说CAS的原子性实际上是对CPU实现独占的,比起用synchronized重量级锁(因为高并发竞争,sync就会升级为重量级锁),这里的排他时间要短很多;而且直接锁CPU总线,是在操作系统层面的完成的,不涉及用户态和内核态的切换。该怎么操作了?JavaAPI底层有一个Unsafe类,里面的方法都是native的,通过C++来调用,最后作用到锁CPU的总线,而synchronized是用一个阻塞队列来阻塞过来竞争的线程,故而细粒度水更细,大家也就清晰了

synchronized详解:高并发之深度解析对象与Sync

package threadSafe.sellticket;

public class SellTicket implements Runnable {

//    private volatile AtomicInteger ticket = new AtomicInteger(100);
      private int ticket = 100;
    @Override
    public void run() {
        while (true) {
            synchronized (this){
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (ticket > 0) {
                    System.out.println(Thread.currentThread().getName() + "正在出售第" + ticket+ "张票");
                    ticket--;
                }
            }
        }
    }
}

 窗口1正在出售第100张票
窗口2正在出售第99张票
窗口3正在出售第98张票
窗口3正在出售第97张票
窗口2正在出售第96张票
窗口1正在出售第95张票
窗口1正在出售第94张票
窗口2正在出售第93张票
窗口3正在出售第92张票
窗口3正在出售第91张票
窗口2正在出售第90张票
窗口1正在出售第89张票
窗口2正在出售第88张票
窗口3正在出售第87张票
窗口2正在出售第86张票
窗口1正在出售第85张票
窗口2正在出售第84张票
窗口3正在出售第83张票
窗口2正在出售第82张票
窗口2正在出售第81张票
窗口2正在出售第80张票
窗口2正在出售第79张票
窗口1正在出售第78张票
窗口2正在出售第77张票
窗口2正在出售第76张票
窗口2正在出售第75张票
窗口2正在出售第74张票
窗口2正在出售第73张票
窗口3正在出售第72张票
窗口2正在出售第71张票
窗口2正在出售第70张票
窗口2正在出售第69张票
窗口2正在出售第68张票
窗口2正在出售第67张票
窗口1正在出售第66张票
窗口2正在出售第65张票
窗口2正在出售第64张票
窗口3正在出售第63张票
窗口2正在出售第62张票
窗口2正在出售第61张票
窗口2正在出售第60张票
窗口1正在出售第59张票
窗口1正在出售第58张票
窗口1正在出售第57张票
窗口1正在出售第56张票
窗口2正在出售第55张票
窗口2正在出售第54张票
窗口2正在出售第53张票
窗口2正在出售第52张票
窗口2正在出售第51张票
窗口3正在出售第50张票
窗口3正在出售第49张票
窗口3正在出售第48张票
窗口2正在出售第47张票
窗口1正在出售第46张票
窗口1正在出售第45张票
窗口2正在出售第44张票
窗口3正在出售第43张票
窗口3正在出售第42张票
窗口3正在出售第41张票
窗口3正在出售第40张票
窗口2正在出售第39张票
窗口1正在出售第38张票
窗口1正在出售第37张票
窗口1正在出售第36张票
窗口2正在出售第35张票
窗口2正在出售第34张票
窗口2正在出售第33张票
窗口3正在出售第32张票
窗口2正在出售第31张票
窗口2正在出售第30张票
窗口2正在出售第29张票
窗口2正在出售第28张票
窗口1正在出售第27张票
窗口1正在出售第26张票
窗口1正在出售第25张票
窗口1正在出售第24张票
窗口1正在出售第23张票
窗口2正在出售第22张票
窗口2正在出售第21张票
窗口3正在出售第20张票
窗口3正在出售第19张票
窗口3正在出售第18张票
窗口3正在出售第17张票
窗口3正在出售第16张票
窗口2正在出售第15张票
窗口1正在出售第14张票
窗口1正在出售第13张票
窗口1正在出售第12张票
窗口2正在出售第11张票
窗口2正在出售第10张票
窗口3正在出售第9张票
窗口3正在出售第8张票
窗口2正在出售第7张票
窗口1正在出售第6张票
窗口2正在出售第5张票
窗口2正在出售第4张票
窗口3正在出售第3张票
窗口2正在出售第2张票
窗口2正在出售第1张票 

后期我会慢慢优化这个内容,精益求精,也希望大家多多批评指正,共同完善! 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值