第四节:并发编程之Atomic&Unsafe魔法类
Posted qianbing
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第四节:并发编程之Atomic&Unsafe魔法类相关的知识,希望对你有一定的参考价值。
原子操作
处理器自动保证基本内存操作的原子性,如对同一个缓存行里进行16/32/64位的操作是原子的。
复杂的内存操作处理器不能自动保证其原子性,比如跨总线宽度,跨多个缓存行,跨页表的访问。
Atomic
在Atomic包里一共有12个类,四种原子更新方式,原子更新基本类型,原子更新数组,原子更新引用,原子更新字段, Atomic包里的类基本都是使用Unsafe实现的包装类。
- 基本类:AtomicInteger、AtomicLong、AtomicBoolean;
- 引用类型:AtomicReference、AtomicReference的ABA实例、AtomicStampedRerence、AtomicMarkableReference;
- 数组类型:AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray
- 属性原子修改器(Updater):AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicReferenceFieldUpdater
AtomicInteger.java
import java.util.concurrent.atomic.AtomicInteger; public class AtomicIntegerTest { static AtomicInteger atomicInteger = new AtomicInteger(); public static void main(String[] args) { for (int i = 0; i<10; i++){ new Thread(new Runnable() { @Override public void run() { atomicInteger.incrementAndGet(); } }).start(); } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("自加10次数值:--->"+atomicInteger.get()); } }
ABA问题
import java.util.concurrent.atomic.AtomicInteger; public class AtomicAbaProblemTest { static AtomicInteger atomicInteger = new AtomicInteger(1); public static void main(String[] args) { Thread main = new Thread(new Runnable() { @Override public void run() { int a = atomicInteger.get(); System.out.println("操作线程"+Thread.currentThread().getName()+"--修改前操作数值:"+a); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } boolean isCasSuccess = atomicInteger.compareAndSet(a,2); if(isCasSuccess){ System.out.println("操作线程"+Thread.currentThread().getName()+"--Cas修改后操作数值:"+atomicInteger.get()); }else{ System.out.println("CAS修改失败"); } } },"主线程"); Thread other = new Thread(new Runnable() { @Override public void run() { atomicInteger.incrementAndGet();// 1+1 = 2; System.out.println("操作线程"+Thread.currentThread().getName()+"--increase后值:"+atomicInteger.get()); atomicInteger.decrementAndGet();// atomic-1 = 2-1; System.out.println("操作线程"+Thread.currentThread().getName()+"--decrease后值:"+atomicInteger.get()); } },"干扰线程"); main.start(); other.start(); } }
解决ABA问题-- AtomicStampedReference
import java.util.concurrent.atomic.AtomicStampedReference; public class AtomicStampedRerenceTest { private static AtomicStampedReference<Integer> atomicStampedRef = new AtomicStampedReference<>(1, 0); public static void main(String[] args){ Thread main = new Thread(() -> { int stamp = atomicStampedRef.getStamp(); //获取当前标识别 System.out.println("操作线程" + Thread.currentThread()+ "stamp="+stamp + ",初始值 a = " + atomicStampedRef.getReference()); try { Thread.sleep(1000); //等待1秒 ,以便让干扰线程执行 } catch (InterruptedException e) { e.printStackTrace(); } boolean isCASSuccess = atomicStampedRef.compareAndSet(1,2,stamp,stamp +1); //此时expectedReference未发生改变,但是stamp已经被修改了,所以CAS失败 System.out.println("操作线程" + Thread.currentThread() + "stamp="+stamp + ",CAS操作结果: " + isCASSuccess); },"主操作线程"); Thread other = new Thread(() -> { int stamp = atomicStampedRef.getStamp(); atomicStampedRef.compareAndSet(1,2,stamp,stamp+1); System.out.println("操作线程" + Thread.currentThread() + "stamp="+atomicStampedRef.getStamp() +",【increment】 ,值 = "+ atomicStampedRef.getReference()); stamp = atomicStampedRef.getStamp(); atomicStampedRef.compareAndSet(2,1,stamp,stamp+1); System.out.println("操作线程" + Thread.currentThread() + "stamp="+atomicStampedRef.getStamp() +",【decrement】 ,值 = "+ atomicStampedRef.getReference()); },"干扰线程"); main.start(); other.start(); } }
AtomicIntegerArray -- 拷贝副本,修改副本数据
import java.util.concurrent.atomic.AtomicIntegerArray; public class AtomicIntegerArrayTest { static int[] value = new int[]{1,2}; static AtomicIntegerArray aiArray = new AtomicIntegerArray(value); public static void main(String[] args) { aiArray.getAndSet(0,3); System.out.println(aiArray.get(0)); System.out.println(value[0]); if(aiArray.get(0) != value[0]){ System.out.println("是否相等"); } } }
属性原子修改器(updater)
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; public class AtomicIntegerFieldUpdateTest { static AtomicIntegerFieldUpdater aifu = AtomicIntegerFieldUpdater.newUpdater(Student.class,"old"); public static void main(String[] args) { Student stu = new Student("laoWang",18); System.out.println(aifu.getAndIncrement(stu)); System.out.println(aifu.get(stu)); } static class Student{ private String name; public volatile int old; public Student(String name ,int old){ this.name = name; this.old = old; } public String getName() { return name; } public int getOld() { return old; } } }
Unsafe工具类
public class UnsafeInstance { public static Unsafe reflectGetUnsafe() { try { Field field = Unsafe.class.getDeclaredField("theUnsafe"); field.setAccessible(true); return (Unsafe) field.get(null); } catch (Exception e) { e.printStackTrace(); } return null; } }
Unsafe
Unsafe是位于sun.misc包下的一个类,主要提供一些用于执行低级别、不安全操作的方法,如直接访问系统内存资源、自主管理内存资源等,这些方法在提升Java运行效率、增强Java语言底层资源操作能力方面起到了很大的作用。
Unsafe类为一单例实现,提供静态方法getUnsafe获取Unsafe实例,当且仅当调用getUnsafe方法的类为引导类加载器所加载时才合法,否则抛出SecurityException异常。
如何获取Unsafe
1、把调用Unsafe相关方法的类Demo所在jar包路径追加到默认的bootstrap路径中,使得A被引导类加载器加载
java -Xbootclasspath/Demo:${path} // 其中path为调用Unsafe相关方法的类所在jar包路径
2、通过反射获取单例对象theUnsafe
Unsafe功能
CAS
线程调度
ThreadParkerTest,java
public class ThreadParkerTest { public static void main(String[] args) { /*Thread t = new Thread(new Runnable() { @Override public void run() { System.out.println("thread - is running----"); LockSupport.park();//阻塞当前线程 System.out.println("thread is over-----"); } }); t.start(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } LockSupport.unpark(t);//唤醒指定的线程*/ //拿出票据使用 LockSupport.park(); System.out.println("main thread is over"); //相当于先往池子里放了一张票据 LockSupport.unpark(Thread.currentThread());//Pthread_mutex System.out.println("im running step 1"); } }
ObjectMonitor.java
public class ObjectMonitorTest { static Object object = new Object(); /* public void method1(){ unsafe.monitorEnter(object); } public void method2(){ unsafe.monitorExit(object); }*/ public static void main(String[] args) { /*synchronized (object){ }*/ Unsafe unsafe = UnsafeInstance.reflectGetUnsafe(); unsafe.monitorEnter(object); //业务逻辑写在此处之间 unsafe.monitorExit(object); } }
内存屏障
FenceTest
public class FenceTest { public static void main(String[] args) { UnsafeInstance.reflectGetUnsafe().loadFence();//读屏障 UnsafeInstance.reflectGetUnsafe().storeFence();//写屏障 UnsafeInstance.reflectGetUnsafe().fullFence();//读写屏障 } }
内存操作
DirectMemoryAccessTest.java
public class DirectMemoryAccessTest { public static void main(String[] args) { Unsafe unsafe = UnsafeInstance.reflectGetUnsafe(); long oneHundred = 1; byte size = 1; /* * 调用allocateMemory分配内存 */ long memoryAddress = unsafe.allocateMemory(size); /* * 将1写入到内存中 */ unsafe.putAddress(memoryAddress, oneHundred); /* * 内存中读取数据 */ long readValue = unsafe.getAddress(memoryAddress); System.out.println("value : " + readValue); } }
以上是关于第四节:并发编程之Atomic&Unsafe魔法类的主要内容,如果未能解决你的问题,请参考以下文章
《Pro Android Graphics》读书笔记之第四节