「javacas原理」javacas是什么意思

博主:adminadmin 2022-12-06 10:06:10 84

今天给各位分享javacas原理的知识,其中也会对javacas是什么意思进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!

本文目录一览:

ReentrantLock的底层实现原理

ReentrantLock主要利用CAS+AQS队列来实现。它支持公平锁和非公平锁,两者的实现类似。

CAS:Compare and Swap,比较并交换。CAS有3个操作数:内存值V、预期值A、要修改的新值B。 当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则重新获取内存地址V的当前值,并重新计算想要修改的值(重新尝试的过程被称为自旋) 。修改变量的操作是一个原子操作,要么完成修改,要么完全没改;CAS被广泛的应用在Java的底层实现中。 在Java中,CAS主要是由sun.misc.Unsafe这个类通过JNI调用CPU底层指令实现

AbstractQueuedSynchronizer简称AQS,是一个用于构建锁和同步容器的框架。事实上concurrent包内许多类都是基于AQS构建,例如ReentrantLock,Semaphore,CountDownLatch,ReentrantReadWriteLock,FutureTask等。AQS解决了在实现同步容器时设计的大量细节问题。

AQS使用一个FIFO的队列表示排队等待锁的线程,队列头节点称作“哨兵节点”或者“哑节点”,它不与任何线程关联。其他的节点与等待线程关联,每个节点维护一个等待状态waitStatus

ReentrantLock的基本实现可以概括为: 先通过CAS尝试获取锁。如果此时已经有线程占据了锁,那就加入AQS队列并且被挂起。当锁被释放之后,排在CLH队列队首的线程会被唤醒,然后CAS再次尝试获取锁。 在这个时候,如果:

非公平锁 :如果同时还有另一个线程进来尝试获取,那么有可能会让这个线程抢先获取;

公平锁 :如果同时还有另一个线程进来尝试获取,当它发现自己不是在队首的话,就会排到队尾,由队首的线程获取到锁。

CAS单点登录原理分析(一)

一,业务分析

在分布式系统架构中,假设把上述的三个子系统部署在三个不同的服务器上。前提是用户登录之后才能访问这些子系统。那么使用传统方式,可能会存在这样的问题:

1.当访问用户中心,需要用户登录帐号

2.当访问购物车,还需要用户登录帐号

3.当访问商品结算,又一次需要用户登录帐号

访问每一个子系统都需要用户登录帐号,这样的体验对于用户来说是极差。而使用单点登录就可以很好地解决上述的问题。

二,单点登录

单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一。SSO 的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。

我们目前的系统存在诸多子系统,而这些子系统是分别部署在不同的服务器中,那么使用传统方式的 session 是无法解决的,我们需要使用相关的单点登录技术来解决。

第一步 :用户访问应用系统1。过滤器判断用户是否登录,没有登录,则重定向(302)到认证系统去进行认证操作。

第二步 :重定向到认证系统,显示登录界面,用户输入用户名密码。认证系统将用户登录的信息记录到服务器的session中。

第三步 :认证系统给浏览器发送一个特殊的凭证ticket,浏览器将凭证交给应用系统1,应用系统1则拿着浏览器交给他的凭证ticket去认证系统验证凭证ticket是否有效。凭证ticket若是有效,将用户信息保存到应用系统1的session中一份,并告知应用系统1,用户通过认证。

第四步 :用户通过认证,浏览器与网站之间进行正常的访问。

第五步 :当用户再次访问应用系统1,由于应用系统1的session中有用户信息,所以就不用经过认证系统认证,就可以直接访问应用系统1了。

第六步 :当用户再去访问其他应用系统时,浏览器会带着凭证ticket过去,其他应用系统到认证系统验证凭证,凭证ticket若是有效,将用户信息保存到其他应用系统的session中一份,并告知其他应用系统,用户通过认证。

第七步 :用户通过认证,浏览器与网站之间进行正常的访问。

第八步 :当用户再次访问其他应用系统,由于其他应用系统的session中有用户信息,所以就不用经过认证系统认证,就可以直接访问其他应用系统了。

三、Yelu大学研发的CAS(Central Authentication Server)

1.什么是CAS?

CAS 是 Yale 大学发起的一个开源项目,旨在为 Web 应用系统提供一种可靠的单点登录方法,CAS 在 2004 年 12 月正式成为 JA-SIG 的一个项目。CAS 具有以下特点:

【1】开源的企业级单点登录解决方案。

【2】CAS Server 为需要独立部署的 Web 应用。这个CAS框架已经提供

【3】CAS Client 支持非常多的客户端(这里指单点登录系统中的各个 Web 应用),包括Java, .Net, PHP, Perl, Apache, uPortal, Ruby 等。

从结构上看,CAS 包含两个部分: CAS Server 和 CAS Client。CAS Server 需要独立部署,主要负责对用户的认证工作;CAS Client 负责处理对客户端受保护资源的访问请求,需要登录时,重定向到 CAS Server。下图是 CAS 最基本的协议过程:

2.CAS的详细登录流程

该图主要描述

1.第一次访问

2.在登录状态下第二次访问

3.在登录状态下第一次访问

下面对图中序号代表的操作进行说明

当用户第一次访问

序号1: 用户请求,会经过AuthenticationFilter认证过滤器(在cas client 的web.xml中配置)

主要作用:判断是否登录,如果没有登录则重定向到认证中心。

大概知道这个就行,CAS的具体实现会在以后的博客中写道

序号2:  AuthenticationFilter发现用户没有登录,则返回浏览器重定向地址。

重定向的地址就是认证服务器CAS Server的地址,后面的参数是我们请求的客户端地址,这个参数目的就是为了认证成功以后,根据这个参数的地址重定向回请求的客户端

序号3:  浏览器根据响应回来的重定向地址,向cas.xiaogui.com认证系统发出请求

序号4:  认证系统cas.xiaogui.com接收请求,响应登陆页面

序号5: :用户登陆页面输入用户名密码,提交请求

序号6: :CAS Server 认证服务器接收用户名和密码,就行验证,验证逻辑CAS Server 已经实现,并响应给浏览器信息

这里的用户名,密码不需要关心,后续会讲到

图中1,2部分表示序号5 输入的用户名,密码,以及发出的请求。当认证服务器验证通过之后,根据请求参数service的值,进行重定向,其实就是回到了请求的客户端,同时会携带一个ticket令牌参数。同时会在Cookie中设置一个TGC,该cookie是网站认证系统cas.xiaogui.com的cookie,只有访问这个网站才会携带这个cookie过去。

*****注意:这个携带TGC的Cookie是实现CAS单点登录的关键所在!

Cookie中的TGC:向cookie中添加该值的目的是当下次访问cas.xiaogui.com认证系统时,浏览器将Cookie中的TGC携带到服务器,服务器根据这个TGC,查找与之对应的TGT。从而判断用户是否登录过了,是否需要展示登录页面。TGT与TGC的关系就像SESSION与Cookie中SESSIONID的关系。

TGT:Ticket Granted Ticket(俗称大令牌,或者说票根,他可以签发ST)

TGC:Ticket Granted Cookie(cookie中的value),存在Cookie中,根据他可以找到TGT。

ST:Service Ticket (小令牌),是TGT生成的,默认是用一次就生效了。也就是上面数字3处的ticket值。

序号7:  客户端拿到请求中的ticket信息,也就是图中1的位置

然后经过一个ticket过滤器Cas20ProxyReceivingTicketValidationFilter,去认证系统CAS Server判断ticket是否有效

这个过滤器的主要工作就是校验客户端传过来的ticket是否有效

CAS Client 客户端  shopping.xiaogui.com  中web.xml的配置

序号8:  向CAS Server认证系统发出验证ticket的请求,也就是图中2的位置,然后执行ticket验证

序号9:  通过校验之后,把用户信息保存到客户端的session中,并把客户端的SessionID设置在Cookie中,同时告知客户端ticket有效。当用户再次访问该客户端,就可以根据Cookie 中的SessionID找到客户端的Session,获取用户信息,就不用再次进行验证了。也就是图中响应给浏览器的部分。

序号10:  shopping.xiaogui.com客户端接收到cas-server的返回,知道了用户已经登录,ticket有效,告知浏览器可以进行访问。

至此,用户第一次访问流程结束。

当用户第二次访问

序号11: 当用户第二次访问,仍然会经过AuthenticationFilter过滤器,但与第一次访问不同的是此时客户端session中已经存在用户的信息,浏览器中的Cookie会根据SessionID找到Session,获取用户信息,所以不需要进行验证,可以直接访问。

序号12:  客户端告知浏览器可以进行访问。

当用户第一次访问

序号13:   用户向pay.xiaogui.com  CAS Client客户端发出请求

序号14:  :pay.xiaogui.com接收到请求,发现第一次访问,于是给他一个重定向的地址,让他去找认证中心登录。

序号15: 浏览器根据上面响应的地址,发起重定向,因为之前访问过一次了,因此这次会携带上次返回的Cookie:TGC到认证中心。

序号16:  认证中心收到请求,发现TGC对应了一个TGT,于是用TGT签发一个ticket,并且返回给浏览器,让他重定向到pay.xiaogui.comCAS Client客户端。

序号17: 根据上面响应回来的地址,进行重定向到pay.xiaogui.comCAS Client客户端

序号18:  pay.xiaogui.comCAS Client客户端带着ticket去认证中心验证是否有效。

序号19:  认证成功,把用户信息保存到客户端的session中,并把客户端的SessionID设置在Cookie中。当用户下次访问pay.xiaogui.comCAS Client客户端,直接登录,无需验证。

序号20:  告知浏览器可以进行访问

CAS单点登录的原理分析大致就是上述的这些,至于CAS单点登录的具体实现,将在下篇博客中写道。

cas底层原理

CAS 你知道吗?

public class CASDemo {

    public static void main(String[] args) {

        AtomicInteger atomicInteger = new AtomicInteger(666);

        // 获取真实值,并替换为相应的值

        boolean b = atomicInteger.compareAndSet(666, 2019);

        System.out.println(b); // true

        boolean b1 = atomicInteger.compareAndSet(666, 2020);

        System.out.println(b1); // false

        atomicInteger.getAndIncrement();

    }

}

CAS 底层原理?谈谈对 UnSafe 的理解?

getAndIncrement();

/**

* Atomically increments by one the current value.

*

* @return the previous value

*/

public final int getAndIncrement() {

    return unsafe.getAndAddInt(this, valueOffset, 1);

}

引出一个问题:UnSafe 类是什么?

UnSafe 类

public class AtomicInteger extends Number implements java.io.Serializable {

    private static final long serialVersionUID = 6214790243416807050L;

    // setup to use Unsafe.compareAndSwapInt for updates

    private static final Unsafe unsafe = Unsafe.getUnsafe();

    private static final long valueOffset;

    static {

        try {

            // 获取下面 value 的地址偏移量

            valueOffset = unsafe.objectFieldOffset

                (AtomicInteger.class.getDeclaredField("value"));

        } catch (Exception ex) { throw new Error(ex); }

    }

    private volatile int value;

// ...

}

Unsafe 是 CAS 的核心类,由于 Java 方法无法直接访问底层系统,而需要通过本地(native)方法来访问, Unsafe 类相当一个后门,基于该类可以直接操作特定内存的数据。Unsafe 类存在于 sun.misc 包中,其内部方法操作可以像 C 指针一样直接操作内存,因为 Java 中 CAS 操作执行依赖于 Unsafe 类。

变量 vauleOffset,表示该变量值在内存中的偏移量,因为 Unsafe 就是根据内存偏移量来获取数据的。

变量 value 用 volatile 修饰,保证了多线程之间的内存可见性。

CAS 是什么

CAS 的全称 Compare-And-Swap,它是一条 CPU 并发。

它的功能是判断内存某一个位置的值是否为预期,如果是则更改这个值,这个过程就是原子的。

CAS 并发原体现在 JAVA 语言中就是 sun.misc.Unsafe 类中的各个方法。调用 UnSafe 类中的 CAS 方法,JVM 会帮我们实现出 CAS 汇编指令。这是一种完全依赖硬件的功能,通过它实现了原子操作。由于 CAS 是一种系统源语,源语属于操作系统用语范畴,是由若干条指令组成,用于完成某一个功能的过程,并且原语的执行必须是连续的,在执行的过程中不允许被中断,也就是说 CAS 是一条原子指令,不会造成所谓的数据不一致的问题。

分析一下 getAndAddInt 这个方法

// unsafe.getAndAddInt

public final int getAndAddInt(Object obj, long valueOffset, long expected, int val) {

    int temp;

    do {

        temp = this.getIntVolatile(obj, valueOffset);  // 获取快照值

    } while (!this.compareAndSwap(obj, valueOffset, temp, temp + val));  // 如果此时 temp 没有被修改,就能退出循环,否则重新获取

    return temp;

}

CAS 的缺点?

循环时间长开销很大

如果 CAS 失败,会一直尝试,如果 CAS 长时间一直不成功,可能会给 CPU 带来很大的开销(比如线程数很多,每次比较都是失败,就会一直循环),所以希望是线程数比较小的场景。

只能保证一个共享变量的原子操作

对于多个共享变量操作时,循环 CAS 就无法保证操作的原子性。

引出 ABA 问题

原子类 AtomicInteger 的 ABA 问题谈一谈?原子更新引用知道吗?

原子引用

public class AtomicReferenceDemo {

    public static void main(String[] args) {

        User cuzz = new User("cuzz", 18);

        User faker = new User("faker", 20);

        AtomicReferenceUser atomicReference = new AtomicReference();

        atomicReference.set(cuzz);

        System.out.println(atomicReference.compareAndSet(cuzz, faker)); // true

        System.out.println(atomicReference.get()); // User(userName=faker, age=20)

    }

}

ABA 问题是怎么产生的

/**

* @program: learn-demo

* @description: ABA

* @author: cuzz

* @create: 2019-04-21 23:31

**/

public class ABADemo {

    private static AtomicReferenceInteger atomicReference = new AtomicReference(100);

    public static void main(String[] args) {

        new Thread(() - {

            atomicReference.compareAndSet(100, 101);

            atomicReference.compareAndSet(101, 100);

        }).start();

        new Thread(() - {

            // 保证上面线程先执行

            try {

                Thread.sleep(1000);

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

            atomicReference.compareAndSet(100, 2019);

            System.out.println(atomicReference.get()); // 2019

        }).start();

    }

}

当有一个值从 A 改为 B 又改为 A,这就是 ABA 问题。

时间戳原子引用

package com.cuzz.thread;

import java.util.concurrent.atomic.AtomicReference;

import java.util.concurrent.atomic.AtomicStampedReference;

/**

* @program: learn-demo

* @description: ABA

* @author: cuzz

* @create: 2019-04-21 23:31

**/

public class ABADemo2 {

    private static AtomicStampedReferenceInteger atomicStampedReference = new AtomicStampedReference(100, 1);

    public static void main(String[] args) {

        new Thread(() - {

            int stamp = atomicStampedReference.getStamp();

            System.out.println(Thread.currentThread().getName() + " 的版本号为:" + stamp);

            try {

                Thread.sleep(1000);

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

            atomicStampedReference.compareAndSet(100, 101, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1 );

            atomicStampedReference.compareAndSet(101, 100, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1 );

        }).start();

        new Thread(() - {

            int stamp = atomicStampedReference.getStamp();

            System.out.println(Thread.currentThread().getName() + " 的版本号为:" + stamp);

            try {

                Thread.sleep(3000);

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

            boolean b = atomicStampedReference.compareAndSet(100, 2019, stamp, stamp + 1);

            System.out.println(b); // false

            System.out.println(atomicStampedReference.getReference()); // 100

        }).start();

    }

}

我们先保证两个线程的初始版本为一致,后面修改是由于版本不一样就会修改失败

CAS原理以及CAS带来的三大问题

参考:

CAS :Compare and Swap,即比较再交换。

CAS算法理解 :CAS是一种无锁算法,CAS有3个操作数,内存值E,旧的预期值V,要修改的新值N。当且仅当预期值V和内存值E相同时,将内存值E修改为N,否则什么都不做。

CAS算法图解 :

上图描述了CAS的原理,以及带来的三大问题以及问题出现的位置。

1.ABA问题

因为CAS需要在操作值的时候,检查值有没有发生变化,如果没有发生变化则更新,但是如果一个值原来是A,变成了B,又变成了A,那么CAS进行检查的时候发现它的值没有发生变化,但是实际上却变化了。ABA问题的解决思路就是使用版本号。在变量前面加上版本号,每次变量更新的时候把版本号加1,那么A-B-A就会变成1A-2B-3A。从Java 1.5开始,JDK的Atomic包里提供了一个类AtomicStampedReference来解决ABA问题。这个类的compareAndSet方法的作用是首先检查当前引用是否等于预期引用,并且检查当前的标志是否等于预期标志,如果全部相等,则以原子方式将该应用和该标志的值设置为给定的更新值。

2.循环时间长开销大

自旋CAS如果长时间不成功,会给CPU带来非常大的执行开销,如果JVM能支持处理器提供的pause指令,那么效率会有一定的提升。pause指令有两个作用:第一,它可以延迟流水线执行指令(de-pipeline),使CPU不会消耗过多的执行资源,延迟的时间取决于具体实现的版本,在一些处理器上延迟时间是零;第二,它可以避免在循环的时候因内存顺序冲突(Memory Order Violation)而引起CPU流水线被清空,从而提高CPU的实行效率。

3.只能保证一个共享变量的原子操作

当对一个共享变量执行操作时,我们可以使用循环CAS的方式来保证原子操作,但是对多个共享变量操作时,循环CAS就无法保证操作的原子性,这个时候可以用锁。还有一个取巧的办法,就是把多个共享变量合并成一个共享变量来操作。比如,有两个共享变量i=2,j=a,合并一下ji=2a,然后用CAS来操作ij。从Java 1.5开始,JDK提供了AtomicReference类来保证引用对象之前的原子性,就可以把多个变量放在一个对象里来进行CAS操作。

JAVA中如何保证线程安全以及主键自增有序

JAVA中如何保证线程安全以及主键自增有序

一、常见场景

多个线程针对一个i进行主键自增。多线程下如果不做安全策略,将会导致各个现成获取的i值重复,导致脏数据

常见策略

1、增加syschroize进行线程同步

2、使用lock、unlock处理

3、使用reetrantent 锁进行锁定

缺点:容易造成性能低下,或者编写代码容易造成死锁

二、新方案

jdk新提供的功能,atomicInteger(还有其他一atomic开头的原子性操作类)

AtomicInteger,一个提供原子操作的Integer的类。在Java语言中,++i和i++操作并不是线程安全的,在使用的时候,不可避免的会用到synchronized关键字。而AtomicInteger则通过一种线程安全的加减操作接口。

原理:通过java的CAS compare and swap,简称cas原语进行操作提升性能,这个也号称乐观锁,不阻塞

观锁实际上并不加锁,当计算遇到冲突或者说前后不一致时会重试 直到成功

CAS有3个操作数 内存值V 要跟内存值做比较的值A 和 新值 B

[html] view plain copy

while(true){

if(V == A){

V = B;

return ;

}else{

A = V;

}

}

CAS的操作对象为volatile类型

volatile类型变量是:CPU直接读写变量所在的内存 而不是把变量copy到寄存器操作

这样对变量的操作所有线程都是可见的

这样做的结果是减少了并发时冲突的概率 但不能完全避免

cas机制原理

Cas机制原理,简单来说是使用一个期望值来和当前变量的值进行比较,如果当前的变量值与我们期望的值相等,就用一个新的值来更新当前变量的值。

CAS有三个操作数:内存值V、旧的预期值A、要修改的值B,当且仅当预期值A和内存值V相同时(条件),将内存值修改为B并返回true,否则条件不符合返回false。条件不符合说明该变量已经被其它线程更新。

cas优点:如一描述在并发量不是很高时cas机制会提高效率。

cas缺点:循环时间开销太大:如果CAS长时间执行不成功,则会给CPU带来交大的执行开销。处理器提供一种pause指令可以缓解这部分问题,pause指令有两个作用,第一它可以延迟流水线执行指令(de-pipeline),使CPU不会消耗过多的执行资源,延迟的时间取决于具体实现的版本,在一些处理器上延迟时间是零。第二它可以避免在退出循环的时候因内存顺序冲突(memory order violation)而引起CPU流水线被清空(CPU pipeline flush),从而提高CPU的执行效率。

只能保证一个共享变量的原操作。如果需要对多个共享变量进行同步,就得使用锁,或者将几个共享变量封装起来,使用CAS来进行同步。从Java1.5开始JDK提供了AtomicReference类来保证引用对象之间的原性,你可以把多个变量放在一个对象里来进行CAS操作。

javacas原理的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于javacas是什么意思、javacas原理的信息别忘了在本站进行查找喔。

The End

发布于:2022-12-06,除非注明,否则均为首码项目网原创文章,转载请注明出处。