自旋锁、CAS、悲观锁、乐观锁

本文介绍了Java并发编程中的自旋锁和CAS(Compare And Swap)机制。自旋锁用于确保线程按特定顺序执行,例如在示例中,确保第三个线程最后执行。CAS是一种乐观锁实现,避免了悲观锁的阻塞,但可能导致CPU开销增加和ABA问题。文中还展示了如何使用AtomicReference实现自旋锁的简单示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1.自旋

2、CAS

3、自旋锁应用示例 仿 Lock

一、自旋

有三个线程,我想要第三个线程始终满足最后一个执行,那么我可以采取只要前两个线程没有执行完毕,我就在第三个线程前面始终来一个自旋等待,只要线程的数量自旋到只剩一个的时候,就让第三个线程执行

//自旋等待例子

public static void main(String[] args) {
					new Thread(new Runnable() {
						public void run() {
							System.out.println(Thread.currentThread().getName()+ " 开始执行");
							try {Thread.sleep(3000);}catch(Exception e) {}
							System.out.println(Thread.currentThread().getName()+ " 执行结束");
							
						}
					}).start();
					
					new Thread(new Runnable() {
						public void run() {
							System.out.println(Thread.currentThread().getName()+ " 开始执行");
							try {Thread.sleep(3000);}catch(Exception e) {}
							System.out.println(Thread.currentThread().getName()+ " 执行结束");
							
						}
					}).start();
					
				
					while(Thread.activeCount()!=1) {
						//自旋等待
					}
					
					System.out.println("全部执行完毕");
				}

二、CAS

1)悲观锁和乐观锁

 == 悲观锁 ==
        总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都
         会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,
        其它线程阻塞,用完后再把资源转让给其它线程)。

        传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都
        是在做操作之前先上锁。
 == 乐观锁 ==
              总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在
              更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和
              CAS   算法实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量,

             像数据库提供的类似于write_condition机制,其实都是提供的乐观锁

2)Synchronized的问题

        synchronized保证了线程的安全,但在某些情况下,不是一个最优的选择
        synchronized 关键字会让没有得到锁资源的线程进入BLOCKED状态,而后在争夺到锁资源后恢复为RUNNABLE状态,
        这个过程中涉及到操作系统用户模式和内核模式的转换,代价比较高。尽管Java1.6 为Synchronized做了优化,
        增加了从偏向锁到轻量级锁再到重量级锁的过度,但是在最终转变为重量级锁之后,性能仍然较低

  
   3) 什么是CAS
    
                CAS是英文单词 Compare And Swap 的缩写,翻译过来就是比较并替换。
                CAS机制当中使用了3个基本操作数:内存地址V,旧的预期值A,要修改的新值B。
                更新一个变量的时候,只有当变量的预期值A和内存地址V当中的实际值相同时,才会将内存地址V对应的值修改为B。

                用unsafe提供了原子性操作方法。

                从思想上来说,Synchronized属于悲观锁,悲观地认为程序中的并发情况严重,所以严防死守。
                CAS属于乐观锁,乐观地认为程序中的并发情况不那么严重,所以让线程不断去尝试更新。

                CAS的缺点:
                
                1.CPU开销较大
                    在并发量比较高的情况下,如果许多线程反复尝试更新某一个变量,却又一直更新不成功,循环往复,会给CPU带来很大的压力。
                
                2.不能保证代码块的原子性
                    CAS机制所保证的只是一个变量的原子性操作,而不能保证整个代码块的原子性。比如需要保证3个变量共同进行原子性的更新,就不得不使用Synchronized了。
            
                3.ABA问题

                    当一个值从A更新成B,又更新会A,普通CAS机制会误判通过检测。

                    利用版本号比较可以有效解决ABA问题
                    从Java1.5 开始JDK的atomic包里提供了一个类AtomicStampedReference来解决ABA问题。
                    这个类的compareAndSet方法作用是首先检查当前引用是否等于预期引用,并且当前标志是否等于预期标志,
                    如果全部相等,则以原子方式将该引用和该标志的值设置为给定的更新值。

三、自旋锁应用示例 仿 Lock
          
      

   public class MyLock {
                    AtomicReference<Thread> atomicReference =new AtomicReference<>();
                    
                    public void lock() {
                        Thread thread=Thread.currentThread();
                        
                        while(!atomicReference.compareAndSet(null, thread)) {    
                        }    
                    }
                    
                    public void unlock() {
                        Thread thread=Thread.currentThread();
                        while(! atomicReference.compareAndSet(thread, null)) {    
                        }    
                    }
            }
                    
                public class Test3 {
                    public static void main(String[] args) {
                        SaleThread th=new SaleThread();
                        
                        new Thread(th).start();
                        new Thread(th).start();
                        new Thread(th).start();
                        new Thread(th).start();
                    }
                }
                
                class SaleThread implements Runnable{
                    int ticket=100;
                    MyLock lock=new MyLock();
                    
                    public void run() {    
                        while(true) {
                            try {
                                lock.lock();
                            
                                if(ticket>0) {
                                    try {Thread.sleep(10);}catch(Exception ex) {}
                                    System.out.println(Thread.currentThread().getName()+" 卖到第 " + ticket--  +" 张票 ");
                                }
                                else {
                                    break;
                                }
                            }
                            catch(Exception ex) {
                                ex.printStackTrace();
                            }
                            finally {
                                lock.unlock();
                            }
                        }    
                    }    
                }
                 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值