1 CAS
1.1 基本介紹
Compare And Set,直譯過來就是比較並設值,解決多線程並行情況下使用鎖造成性能損耗的一種機制,CAS操作包含三個操作數—內存位置(V)、預期原值(A)和新值(B)。如果內存位置的值與預期原值相匹配,那麼處理器會自動將該位置值更新爲新值。否則,處理器不做任何操作。
/**
* Atomically sets the value to the given updated value
* if the current value {@code ==} the expected value.
*
* @param expect the expected value
* @param update the new value
* @return {@code true} if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
1.2 案例
public static void main(String[] args) {
//期望12,設置爲20
AtomicInteger atomicInteger=new AtomicInteger(10);
boolean b = atomicInteger.compareAndSet(12, 20);
System.out.println(b);
System.out.println(atomicInteger.get());
System.out.println("#######################");
//期望10,設置爲20
AtomicInteger atomicInteger1=new AtomicInteger(10);
boolean b1 = atomicInteger1.compareAndSet(10, 20);
System.out.println(b1);
System.out.println(atomicInteger1.get());
}
2 Unsafe
2.1 簡介
Java 不能直接訪問操作系統底層,而是通過本地方法來訪問。Unsafe 類提供了硬件級別的原子操作。Unsafe 類在 sun.misc 包下,不屬於 Java 標準。很多 Java 的基礎類庫,包括一些被廣泛使用的高性能開發庫都是基於 Unsafe 類開發,比如 Netty、Hadoop、Kafka 等。
(1) Unsafe 是用於在實質上擴展 Java 語言表達能力、便於在更高層(Java 層)代碼裏實現原本要在更低層(C 層)實現的核心庫功能用的。
(2) 這些功能包括裸內存的申請/釋放/訪問,低層硬件的 atomic/volatile 支持,創建未初始化對象等。
(3) 它原本的設計就只應該被標準庫使用,因此不建議在生產環境中使用。
2.2 獲取Unsafe
public final class UnsafeUtils {
private UnsafeUtils() {
}
/**
* 獲取Unsafe
*/
public static Unsafe getUnsafe() {
try {
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
return (Unsafe) field.get(null);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
3 Unsafe實現CAS鎖
3.1 接口
public interface Counter {
void increment();
long getCounter();
}
3.2 CasCounter
public class CasCounter implements Counter {
private volatile long counter = 0;
private Unsafe unsafe;
private long offset;
public CasCounter() throws Exception {
//獲取unsafe
unsafe = UnsafeUtils.getUnsafe();
//設置偏移量爲counter
offset = unsafe.objectFieldOffset(CasCounter.class.getDeclaredField("counter"));
}
@Override
public void increment() {
long current = counter;
/**
* compareAndSwapLong(Object var1, long var2, long var4, long var6)
* var1:對象,var2:偏移量,var4:expect(期望值),var6:update(更新值)
*/
while (!unsafe.compareAndSwapLong(this, offset, current, current + 1)) {
current=counter;
}
}
@Override
public long getCounter() {
return counter;
}
}
3.3 測試類
/**
* @Description: 每個線程對Counter進行累加MAX_SUM次,MAX_THREAD個線程同時累加
* @Auther: zhurongsheng
* @Date: 2020/4/2 11:15
*/
public class UnsafeTest {
private static final int MAX_THREAD = 1000;
private static final int MAX_SUM = 10000;
public static void main(String[] args) throws Exception {
ExecutorService service = Executors.newFixedThreadPool(MAX_THREAD);
Counter counter = new CasCounter();
for (int i = 0; i < 1000; i++) {
service.submit(new CounterRunnable(counter, MAX_SUM));
}
//關閉不接受新任務
service.shutdown();
//阻塞,直到所有任務執行完畢 或 1小時後中斷
service.awaitTermination(1, TimeUnit.HOURS);
System.out.println("Counter result:" + counter.getCounter());
}
}
4 unsafe創建對象繞過對象的構造
4.1 pojo
class Simple {
public Simple() {
System.out.println("Simple invoke NoArgsConstructor");
}
public void sayHello(){
System.out.println("hello world");
}
}
4.2 測試類
/**
* @Description: 通過Unsafe創建對象可以繞過對象的構造
* @Auther: zhurongsheng
* @Date: 2020/4/2 13:45
*/
public class UnsafeTest {
public static void main(String[] args) throws Exception {
//通過new 直接新建Simple
System.out.println("創建:");
new Simple();
//通過反射創建Simple
System.out.println("反射:");
Simple.class.newInstance();
//通過unsafe
System.out.println("【unsafe】:");
Unsafe unsafe = UnsafeUtils.getUnsafe();
Simple instance = (Simple) unsafe.allocateInstance(Simple.class);
instance.sayHello();
}
}
5 unsafe直接修改私有變量
5.1 pojo
class Simple {
private boolean access = false;
private boolean allow() {
return access == true;
}
public void work() {
if (allow()) {
System.out.println("工作使我快樂");
return;
}
System.out.println("我不要工作,來世我要當一個被子,要麼躺牀上,要麼曬太陽。");
}
}
5.2 測試類
public class UnsafeTest {
public static void main(String[] args) throws Exception {
//1 直接new
System.out.println("直接創建對象:");
Simple simple1 = new Simple();
simple1.work();
System.out.println("###########################");
//2 反射
System.out.println("通過反射直接修改私有變量:");
Simple simple2 = Simple.class.newInstance();
Field access = simple2.getClass().getDeclaredField("access");
access.setAccessible(true);
access.set(simple2,true);
simple2.work();
System.out.println("###########################");
//3 unsafe
System.out.println("通過unsafe修改私有變量:");
Unsafe unsafe = UnsafeUtils.getUnsafe();
Simple simple3 = Simple.class.newInstance();
Field access1 = simple3.getClass().getDeclaredField("access");
//對象,偏移量,設置值
unsafe.putBoolean(simple3,unsafe.objectFieldOffset(access1),true);
simple3.work();
}
}