重生之学Java的第十一天

一、CAS机制

什么是CAS(Compare and Swap)?

CAS就是一种乐观锁的实现方式,翻译过来就是“比较和交换”,是一种无锁的原子操作,具体的实现为Unsafe类 。

在并发编程中,i++(自增)操作时非线程安全的,是因为i++操作不是原子操作,那么怎么保证其原子性呢?

最常见的做法就是加锁。在Java中,synchronized关键字和CAS来实现加锁的效果。synchronized是悲观锁,随着版本迭代更新,synchronized关键字已经完成了“瘦身”,变成了轻量级的锁,但它依旧摆脱不了是悲观锁的命运,线程开始执行第一步的时候就要获取锁,一旦获取到锁,其他的线程进入后就会出现阻塞并等待锁。而CAS就不一样了,CAS是一种乐观锁的实现方式,线程执行的时候不会加上锁,而是在执行的时候默认为没有冲突,然后直到完成某项操作,如果因为冲突失败了就重试,直到成功为止。

乐观锁与悲观锁

悲观锁

对于悲观锁来说,它总是认为每次访问共享资源时会发生冲突,所以必须对每次数据操作加上锁,以保证临界区的程序同一时间只能有一个线程在执行。

乐观锁

乐观锁,顾名思义,它是乐观派。乐观锁总是假设对共享资源的访问没有冲突,线程可以不停地执行,无需加锁也无需等待。一旦多个线程发生冲突,乐观锁通常使用一种称为 CAS 的技术来保证线程执行的安全性。

由于乐观锁假想操作中没有锁的存在,因此不太可能出现死锁的情况,换句话说,乐观锁天生免疫死锁

乐观锁多用于“读多写少“的环境,避免频繁加锁影响性能;

悲观锁多用于”写多读少“的环境,避免频繁失败和重试影响性能。

在 CAS 中,有这样三个值:

V:要更新的变量(var)   E:预期值(expected)  N:新值(new)

二、volitle关键字的使用

volatile 是Java中的一个关键字,用于修饰变量。它主要用于保证可见性和禁止指令重排序。

在多线程环境下,当一个线程修改了共享变量的值后,其他线程可能无法立即看到这个修改。这是因为每个线程都有自己的缓存,如果没有使用合适的同步机制,线程可能会读取到过期的缓存值,从而导致数据不一致的问题。

使用 volatile 关键字可以解决这个问题。当一个变量被声明为 volatile 时,每次对该变量的读写操作都会直接从内存中进行,而不是从线程的缓存中读取或写入。这样可以确保所有线程都能看到最新的值,实现了可见性。

此外,volatile 还禁止了指令重排序优化。在编译器和处理器对代码进行优化时,会对指令顺序进行重排序以提高性能。在某些情况下,这种重排序可能导致多线程程序出现异常行为。通过将变量声明为 volatile,可以防止特定类型的指令重排序,从而避免了潜在的错误。

需要注意的是,volatile 并不能替代锁(synchronized)来实现原子性操作。它只能保证可见性和禁止指令重排序,不能保证复合操作的原子性。如果需要进行原子性操作,应该使用锁或者其他线程安全的方式。

三、线程的生命周期描述

线程的生命周期描述了一个线程从创建到终止的整个过程,它包含以下几个状态:

  1. 新建(New):当我们通过实例化 Thread 类或者实现 Runnable 接口创建一个线程对象时,线程就处于新建状态。此时线程还没有开始执行。

  2. 就绪(Runnable):当调用线程对象的 start() 方法后,线程进入就绪状态。此时线程已经准备好运行,但还需要等待获取 CPU 时间片才能真正开始执行。多个线程被放入可运行线程池中,在操作系统调度之前,无法确定哪个线程会先执行。

  3. 运行(Running):当线程获得 CPU 时间片并开始执行时,线程进入运行状态。此时线程正在执行自己的任务代码。

  4. 阻塞(Blocked):在特定情况下,线程可能会由于某些原因而暂停执行。这种情况下线程进入阻塞状态。例如,线程可能因为等待某个资源、等待用户输入等而被阻塞。当阻塞条件解除时,线程会重新进入就绪状态,等待获取 CPU 时间片。

  5. 等待(Waiting):线程在等待某个特定条件的发生时进入等待状态。线程可以通过调用 Object 类的 wait() 方法、Thread 类的 join() 方法或者调用锁对象的 wait() 方法来进入等待状态。当其他线程修改了特定条件并通知等待线程时,等待线程会被唤醒并进入就绪状态。

  6. 计时等待(Timed Waiting):与等待状态类似,但是在计时等待状态下,线程会等待一段指定的时间。线程可以通过调用 Thread 类的 sleep() 方法、Object 类的 wait(long timeout) 方法、Thread 类的 join(long timeout) 方法或者调用锁对象的 wait(long timeout) 方法来进入计时等待状态。

  7. 终止(Terminated):当线程执行完任务或者发生异常而终止时,线程进入终止状态。一个终止的线程不能再次进入任何其他状态。

需要注意的是,不同的操作系统和JVM实现可能存在差异,因此线程的具体行为可能会有所不同。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值