原子引用解决ABA问题

ABA问题:

简单来说就是你要操作一个值,当这个值为多少的时候你需要进行什么操作,但是这个值在你操作之前已经被改掉了,又被改回来了。其实你操作的值已经经过了很多操作了。

代码介绍:

        AtomicInteger atomicInteger = new AtomicInteger(2022); //底层用的cas
        //public final boolean compareAndSet(int expect, int update)
        //如果期望的值达到了就更新,否则不更新

        //对于写的sql:利用乐观锁解决问题:要知道谁动了线程!
        //=======捣乱的线程=========

    //=======捣乱的线程=========
        new Thread(()->{
            System.out.println(atomicInteger.compareAndSet(2022, 2023));
            System.out.println(atomicInteger.get());
            System.out.println(atomicInteger.compareAndSet(2023, 2022));
            System.out.println(atomicInteger.get());
        },"A").start();
        new Thread(()->{
            System.out.println(atomicInteger.compareAndSet(2022, 6666));
            System.out.println(atomicInteger.get());
        },"B").start();

解决办法:加版本号与乐观锁的实现机制差不多

  AtomicStampedReference<Integer> atomicInteger = new AtomicStampedReference<>(1, 1);

        new Thread(()->{
            int stamp = atomicInteger.getStamp();//获得版本号
            System.out.println("a1=>"+stamp);
            try {
                Thread.sleep(200000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //下面这一段代码跟乐观锁里面的version+1版本号操作一样
            System.out.println(atomicInteger.compareAndSet(1, 2,
                    atomicInteger.getStamp(), atomicInteger.getStamp() + 1));

            System.out.println("a2=>"+atomicInteger.getStamp());

            System.out.println(atomicInteger.compareAndSet(2, 1,
                    atomicInteger.getStamp(), atomicInteger.getStamp() + 1));

            System.out.println("a3=>"+atomicInteger.getStamp());
        },"a").start();

        //与乐观锁的原理相同,由于中间修改过了线程,导致正常的线程不能修改,返回false
        new Thread(()->{
            int stamp = atomicInteger.getStamp();//版本号获取
            System.out.println("b1=>"+stamp);

//            try {
//                TimeUnit.SECONDS.sleep(2);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }

            System.out.println(atomicInteger.compareAndSet(1, 6, stamp, stamp + 1));

            System.out.println("b2=>"+atomicInteger.getStamp());
        },"b").start();

这里需要注意的一点就是Junit测试类线程执行睡眠sleep()后次线程后面的程序不能进行;因为junit执行的程序必须是激活状态的。而sleep是睡眠状态,一旦执行就会自动退出程序。 所以在测试类里使用sleep()等方法是不会生效的。

测试类注意点:测试类的包名需要和启动类保持一致,否则会扫描不到bean

LockSupport.park()会使线程进入到什么状态?

public static void main(String[] args) throws Exception {
    Thread parkThread = new Thread(new Runnable() {
        @Override
        public void run() {

            System.out.println(Thread.currentThread().getName() + "进入park");
            LockSupport.park(this);
            System.out.println(Thread.currentThread().getName() + "解除park");
        }
    }, "parkThread");
    parkThread.start();
}

 我们使用jps来查看目前系统正在运行的线程号:

然后再使用istack命令来查看线程的状态,当然这个线程的状态指的是jvm中的状态,而不是操作系统中的状态。

我们可以看到状态是waiting   ,在操作系统中就是sleep状态。 线程id为0X3008,这是16进制的,转换成10进制,就可以通过这个id查看状态了。

通过两种方式可以解除:

第一种:LockSupport.unpark();

Thread unParkThread = new Thread(new Runnable() {
   @Override
   public void run() {
       System.out.println(Thread.currentThread().getName() + "进入unPark");
       LockSupport.unpark(parkThread);
       System.out.println(Thread.currentThread().getName() + "退出unPark");
   }
}, "unParkThread");

unParkThread.start();

第二种: thread.interrupt()

Thread unParkThread = new Thread(new Runnable() {
     @Override
     public void run() {
         System.out.println(Thread.currentThread().getName() + "进入中断");
         parkThread.interrupt();
         System.out.println(Thread.currentThread().getName() + "退出中断");
     }
 }, "unParkThread");

 unParkThread.start();

关闭端口命令:

查询端口的进程id:

netstat -ano |findstr 8084

杀死进程:

taskkill /t /f /pid 29620

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值