zoukankan      html  css  js  c++  java
  • 第四节:并发编程之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());
        }
    
    }
    View Code

      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();
    
        }
    }
    View Code

     解决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();
        }
    }
    View Code

    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("是否相等");
            }
        }
    
    }
    View Code

    属性原子修改器(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;
            }
        }
    
    }
    View Code

    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;
        }
    }
    View Code

    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");
    
        }
    
    }
    View Code

    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);
    
        }
    
    }
    View Code

    内存屏障

     

     

     

     FenceTest

    public class FenceTest {
    
        public static void main(String[] args) {
    
            UnsafeInstance.reflectGetUnsafe().loadFence();//读屏障
    
            UnsafeInstance.reflectGetUnsafe().storeFence();//写屏障
    
            UnsafeInstance.reflectGetUnsafe().fullFence();//读写屏障
    
        }
    }
    View Code

    内存操作

    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);
        }
    }
    View Code

     

  • 相关阅读:
    常见数据库设计
    团队建设工具
    Java的redis控制台-Jedis
    java常用类总结
    sql可重复执行语句例子
    让simplejson支持datetime类型的序列化
    Python模块的导入以及软件开发规范
    boto3--通过Python的SDK连接aws
    HTML目录:
    Python目录:
  • 原文地址:https://www.cnblogs.com/qianbing/p/12643583.html
Copyright © 2011-2022 走看看