第四节:并发编程之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());
    }

}
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

 

 

 

 

 

以上是关于第四节:并发编程之Atomic&Unsafe魔法类的主要内容,如果未能解决你的问题,请参考以下文章

《Pro Android Graphics》读书笔记之第四节

深入理解java:2.3.1. 并发编程concurrent包 之Atomic原子操作

并发编程之原子类

第四节 模块&库

软件构造 第三章第四节 面向对象编程OOP

第四节:web爬虫之urllib