- 给线程安全下一个明确的定义:当多个线程访问这个对象或者资源时,如果这个对象或资源始终都能表现出数据的一致性的状态,那么就称这个对象或者资源是线程安全的;
数据资源的有无状态化
-
无状态的对象一定是线程安全的。
-
有状态的对象,多线程环境下,多个线程共享资源,且进行的不是原子性操作,这个时候就要考虑线程的安全控制问题
比如:count++,其实是不具备原子性的,因为这个步骤实际会被拆分为三个步骤,即 读取、修改和写入,而这三个步骤有可能在某个时刻因 CPU 时间片的切换问题,而只执行其中一两个步骤,这就不具备原子性。
原子化能力支持
在 Java 中,为了解决这个问题,java.util.concurrent.atomic 包提供了很多的类,来保证数据操作的原子性,比如我们之前的程序可以修改为
-
基本数据类型 AtomicInteger
-
数组类型 AtomicIntegerArray
AtomicInteger integer = new AtomicInteger(0);``integer.incrementAndGet()
内部的原理是采用了 CAS 机制
那么什么是 CAS 机制?
CAS 有人翻译为 Compare And Set 或 Compare And Swap 都是正确的。
多线程并发执行的状态下,锁的状态改变,基本都是使用 CAS 原理,它有一个比较别扭的叫法“CPU 硬件同步原语”,算法是基于 CPU 硬件的,原子性操作,不会被其他线程打断。
CAS 的算法,比较当前值和期望的值是否相等,如果相等,则将当前值赋予一个新值。
再比如修改一个 Boolean 的类型的变量的值,我们也可以采用
private AtomicBoolean atomicBoolean = new AtomicBoolean(false);public void lock(){` `//期望是false,如果是false,则可以修改为true` `atomicBoolean.compareAndSet(false, true);
}
同步锁机制支持
只要程序中存在“先判断,再更新”,那么就要保证这两个操作在一个原子操作里面,才能保证线程安全。
public synchronized int getCount(){
return count++;``}
Java 锁机制的一些特点
监视锁、互斥锁、可重入锁都是在这个锁的特点。
-
监视锁:java 的每一个对象都可以用来做监视锁,也就是为什么我们的 wait、notify 方法定义在 Object 类的原因。
-
互斥锁:表示最多只有一个线程可以持有这把锁。
-
可重入锁:是指当线程 A 请求一个由线程 B 持有的锁时,线程 B 会进入阻塞状态;而如果线程 A 如果再访问另一段代码,而这个代码的锁是已经被线程 A 持有的,这个时候请求是可以成功的,这就叫可重入。
Java 锁机制的简单原理
JVM 为每个锁设置两个属性,获取计数值和所有者线程,当计数值为 0 时,这个锁就被认为是没有被任何线程持有,当线程请求一个未被持有的锁时,JVM 将记录锁的持有者,并且计数值+1。
学习路线:
这个方向初期比较容易入门一些,掌握一些基本技术,拿起各种现成的工具就可以开黑了。不过,要想从脚本小子变成黑客大神,这个方向越往后,需要学习和掌握的东西就会越来越多以下是网络渗透需要学习的内容:
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!