java
- CAS? => compareAndSet 比较并交换
全称为:Compare-And-Swap,它是一条CPU并发原语。功能是判断内存某个位置的值是否为预期值,如果是则更改为新的值,这个过程是原子的。 - Unsafe?是CAS的核心类,由于java方法无法直接访问底层系统,需要通过本地(native)方法来访问,Unsafe相当于一个后门,给予该类可以直接操作特定内存的数据。Unsafe类存在于sun.misc包种,其内部方法操作可以像C的指针一样直接操作内存,因为Java中CAS操作的执行依赖于Unsafe类的方法(Unsafe类中的所有方法都是native修饰的,也就是说Unsafe类中的方法都直接调用操作系统底层资源执行相应任务)
- CAS缺点?①循环时间长开销大;② 只能保证一个共享变量的原子操作;③引出来ABA问题
- ABA问题?狸猫换太子
就是有两个线程A和B。比如线程A对主内存中的变量countA变为了countB,然后又将countB变回了countA。这时候线程B进行CAS操作发现内存中仍然是countA,但他不知道这个countA不是原来的countA- AutomicReference原子引用
class User { private String name; private Integer age; } public class AtomicReferenceDemo { public static void main(String[] args) { User zs = new User("zs", 22); User lisi = new User("lisi", 25); AtomicReference<User> atomicReference = new AtomicReference<>(); atomicReference.set(zs); System.out.println(atomicReference.compareAndSet(zs, lisi) + "\t current user is " + atomicReference.get());// true lisi System.out.println(atomicReference.compareAndSet(zs, lisi) + "\t current user is " + atomicReference.get());// false lisi } }
- AtomicStampedReference版本号原子引用
public class ABADemo { static AtomicReference<Integer> atomicReference = new AtomicReference<>(100); static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100, 1); public static void main(String[] args) { //============ABA问题的产生============= new Thread(() -> { atomicReference.compareAndSet(100, 101); atomicReference.compareAndSet(101, 100); }, "t1").start(); new Thread(() -> { System.out.println(atomicReference.compareAndSet(100, 2022) + "\t atomicReference value is " + atomicReference.get()); }, "t2").start(); //============ABA问题的解决============= new Thread(() -> { // 获取版本号 int stamp = atomicStampedReference.getStamp(); System.out.println(Thread.currentThread().getName() + "\t第一次版本号:" + stamp); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } atomicStampedReference.compareAndSet(100, 101, atomicStampedReference.getStamp(), atomicStampedReference.getStamp()+1); System.out.println(Thread.currentThread().getName() + "\t第二次版本号:" + atomicStampedReference.getStamp()); atomicStampedReference.compareAndSet(101, 100, atomicStampedReference.getStamp(), atomicStampedReference.getStamp()+1); System.out.println(Thread.currentThread().getName() + "\t第三次版本号:" + atomicStampedReference.getStamp()); }, "t3").start(); new Thread(() -> { // 获取版本号 int stamp = atomicStampedReference.getStamp(); System.out.println(Thread.currentThread().getName() + "\t第一次版本号: " + stamp); try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } boolean b = atomicStampedReference.compareAndSet(100, 2022, stamp, stamp + 1); System.out.println(Thread.currentThread().getName() + "\t修改成功否:" + b + "\t当前版本号为:" + atomicStampedReference.getStamp() + "\t当前实际值:" + atomicStampedReference.getReference()); }, "t4").start(); } }
- AutomicReference原子引用
- 集合类不安全?
- 集合类不安全之并发修改异常 ArrayList
解决:①Vector(); ②Collections.synchronizedList(new ArrayList<>());③new CopyOnWriteArrayList<>();(推荐) - 集合类不安全之Set
解决:①Collections.synchronizedSet(new HashSet<>());②new CopyOnWriteArraySet<>();(推荐) - 集合类不安全之Map
解决:①Collections.synchronizedMap(new HashMap<>());②new ConcurrentHashMap<>();(推荐)
- 集合类不安全之并发修改异常 ArrayList
算法
- 数组:存放在连续内存空间上的相同类型数据的集合
- 二分查找:给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/binary-search
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
方法一:定义target在一个左闭右闭区间
class Solution {
public int search(int[] nums, int target) {
int i = 0, j = nums.length - 1;
while (i <= j) {
int mid = i + (j - i) / 2;
if (nums[mid] > target)
j = mid - 1;
else if (nums[mid] < target)
i = mid + 1;
else
return mid;
}
return -1;
}
}
方法二:定义target在一个左闭右开的区间
class Solution {
public int search(int[] nums, int target) {
int i = 0, j = nums.length;
while (i < j) {
int mid = i + (j - i) / 2;
if (nums[mid] > target)
j = mid;
else if (nums[mid] < target)
i = mid + 1;
else
return mid;
}
return -1;
}
}
- 移除元素
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/remove-element
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路:遍历这个数组,如果数组中的元素和传入的值val相等,则continue,直接跳到下一个循环。如果值不相等的话,就将值赋给原数组,下标(定义一个len)从0开始。返回len。
class Solution {
public int removeElement(int[] nums, int val) {
int length = 0;
for (int i = 0; i < nums.length; i++) {
if (nums[i] == val) {
continue;
}
nums[length] = nums[i];
length++;
}
return length;
}
}