码迷,mamicode.com
首页 > 其他好文 > 详细

JUC三

时间:2020-03-10 13:47:00      阅读:67      评论:0      收藏:0      [点我收藏+]

标签:null   编译   valueof   cas   变量   cti   thread   mis   public   

14.常用辅助类

14.1CountDownLatch:减法计数器

package com.ruyidd.auxiliary;

import java.util.concurrent.CountDownLatch;

/**
 */
public class CountDownLatchDemo {

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch downLatch = new CountDownLatch(6);

        for (int i = 0; i < 6; i++) {
            new Thread(()->{
                System.out.println(Thread.currentThread().getName()+" Start");
                downLatch.countDown();//
            }).start();
        }
        downLatch.await();
        //想实现的目标:等待上面的6个线程执行完毕,再执行main线程的End
        System.out.println(Thread.currentThread().getName()+" End");
    }
}

14.2CyclicBarrier:加法计数器

package com.ruyidd.auxiliary;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

/**
 * @author: tianxc
 * @date: 2020-03-09 21:51
 * @desc:
 */
public class CyclicBarrierDemo {
    public static void main(String[] args) {

        CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{
            System.out.println("已经集齐七颗龙珠,召唤神龙!");
        });

        for (int i = 1; i <= 7; i++) {
            new Thread(()->{
                System.out.println(Thread.currentThread().getName()+" 获得一颗龙珠");
                try {
                    cyclicBarrier.await();//阻塞线程
                    System.out.println(Thread.currentThread().getName()+" 线程阻塞了吗?");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            },String.valueOf(i)).start();
        }
    }
}

14.3 Semaphore:信号量

  • acquire()
    • 当一个线程调用acquire方法的时候,就是获取到了一个信号量-1
    • 如果当前为0,就会一直等待下去
  • release()
    • 信号量+1,唤醒等待的线程。
  • 使用场景:多线程共享资源互斥;并发线程的控制。
package com.ruyidd.auxiliary;

import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

/**
 * @author: tianxc
 * @date: 2020-03-09 22:03
 * @desc:
 */
public class SemaphoreDemo {

    public static void main(String[] args) {
        //Semaphore 信号量,可以用来限流
        //模拟三个车位
        Semaphore semaphore = new Semaphore(3);
        //模拟6个车
        for (int i = 1; i <= 6; i++) {
            new Thread(()->{
                try {
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName()+" 获得了车位");
                    TimeUnit.SECONDS.sleep(3);
                    System.out.println(Thread.currentThread().getName()+" 离开了车位");

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    semaphore.release();
                }
            },String.valueOf(i)).start();
        }
    }
}

15. JMM:Java内存模型

JMM只是一个理论。

所有的线程是如何工作的?

技术图片

技术图片

16. volatile

  1. 保证可见性
  2. 不保证原子性
  3. 禁止指令重排

16.1 验证volatile的可见性

package com.ruyidd.jmm;

import java.util.concurrent.TimeUnit;

/**
 * 验证volatile的可见性
 */
public class Demo1 {

    private volatile static int num = 0;
    public static void main(String[] args) throws InterruptedException {
        new Thread(()->{
            while (num==0){

            }
        }).start();

        TimeUnit.SECONDS.sleep(1);
        num = 1;
        System.out.println(num);
    }
}

16.2 验证(volatile不保证原子性)

package com.ruyidd.jmm;

import java.util.concurrent.CountDownLatch;

/**
 * @author: tianxc
 * @date: 2020-03-09 22:28
 * @desc:
 */
public class Demo2 {

    //volatile不保证原子性验证
    private volatile static int num = 0;

    //synchronized
    public static void add(){
        num++;//不是一个原子性的操作
    }

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch downLatch = new CountDownLatch(20000);
        //期望num的值最终是两万
        for (int i = 1; i <= 20; i++) {
            new Thread(()->{
                for (int i1 = 0; i1 < 1000; i1++) {
                    add();
                    downLatch.countDown();
                }
            },String.valueOf(i)).start();
        }
        downLatch.await();
        System.out.println(Thread.currentThread().getName()+" "+num);
    }
}

如何不用锁解决该问题

package com.ruyidd.jmm;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author: tianxc
 * @date: 2020-03-09 22:28
 * @desc:
 */
public class Demo3 {

    //原子类
    private static AtomicInteger atomicInteger = new AtomicInteger();

    public static void add(){
        atomicInteger.getAndIncrement();//原子性操作
    }

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch downLatch = new CountDownLatch(20000);
        //期望num的值最终是两万
        for (int i = 1; i <= 20; i++) {
            new Thread(()->{
                for (int i1 = 0; i1 < 1000; i1++) {
                    add();
                    downLatch.countDown();
                }
            },String.valueOf(i)).start();
        }
        downLatch.await();
        System.out.println(Thread.currentThread().getName()+" "+atomicInteger.get());
    }
}

16.3 论证(volatile禁止指令重排)

指令重排:写的程序不一定是按照程序的顺序执行的

源代码->编译器(优化重排)->指定并行重排->内存系统重排->最终执行。

  1. 单线程一定安全(但是,也不能避免指令重排!)
  2. 处理器在进行重排的时候,会考虑指令之间的依赖性!
int x,y,a,b = 0;

线程1                       线程2
x = a;                     y = b;
b = 1;                     a = 2;
理想的结果: x=0  y = 0

指令重排:
线程1                       线程2
b = 1;                     a = 2;
x = a;                     y = b;

重排后的结果: x=2  y = 1 

指定重排小结:

volatile 可以禁止指令重排!

内存屏障(Memory Barrier):CPU的指令,有两个作用:

  1. 保证特定的执行顺序
  2. 保证某些变量的内存可见性(volatile就是用这个特性实现的。)

技术图片

17. 单例模式

DCL 懒汉式:双检锁懒汉式

package com.ruyidd.single;

import java.lang.reflect.Constructor;

/**
 * @author: tianxc
 * @date: 2020-03-09 22:56
 * @desc:
 */
public class LazyMan {

    private static boolean aldkfakjdfaklsdjf = false;

    private LazyMan(){
        synchronized (LazyMan.class){
            if (aldkfakjdfaklsdjf==false){
                aldkfakjdfaklsdjf = true;
            }else{
                throw new RuntimeException("不要试图破坏单例模式");
            }
        }
    }

    //禁止指令重排
    private volatile static LazyMan lazyMan;

    public static LazyMan getInstace(){
        if(lazyMan==null){
            synchronized (LazyMan.class){
                if(lazyMan==null){
                    //用volatile禁止指令操作
                    lazyMan = new LazyMan();
                    /**
                     * Java 创建一个对象
                     *  1.分配内存空间
                     *  2.执行构造方法,创建对象
                     *  3.将对象指向空间
                     */
                }
            }
        }
        return lazyMan;
    }


    public static void main(String[] args) throws Exception {
        Class<LazyMan> clazz = LazyMan.class;
        Constructor<LazyMan> declaredConstructor = clazz.getDeclaredConstructor(null);
        LazyMan lazyMan1 = declaredConstructor.newInstance();
        LazyMan lazyMan2 = declaredConstructor.newInstance();
        System.out.println(lazyMan1.hashCode());
        System.out.println(lazyMan2.hashCode());

    }

}

在jdk源码没有修改的前提下,枚举是单例模式最安全的

package com.ruyidd.single;

import java.lang.reflect.Constructor;

/**
 * @author: tianxc
 * @date: 2020-03-09 23:08
 * @desc:
 */
public enum SingleEnum {

    INSTANCE;

    public SingleEnum getInstance(){
        return INSTANCE;
    }
}

class SingleEnumDemo{
    public static void main(String[] args) throws Exception {
//        Constructor<SingleEnum> declaredConstructor = SingleEnum.class.getDeclaredConstructor(null);
//        Cannot reflectively create enum objects
//        Exception in thread "main" java.lang.NoSuchMethodException: com.ruyidd.single.SingleEnum.<init>()
//        SingleEnum singleEnum = declaredConstructor.newInstance();
//        System.out.println(singleEnum);


        Constructor<SingleEnum> declaredConstructor = SingleEnum.class.getDeclaredConstructor(String.class,int.class);
        declaredConstructor.setAccessible(true);
        //Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects
        SingleEnum singleEnum = declaredConstructor.newInstance();
        System.out.println(singleEnum);
    }
}

18.CAS:比较并交换

package com.ruyidd.jmm;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author: tianxc
 * @date: 2020-03-09 23:15
 * @desc:
 */
public class Demo4 {

    public static void main(String[] args) {
//        AtomicInteger 默认为0
        AtomicInteger atomicInteger = new AtomicInteger(5);

//        compareAndSet  cas 比较并交换
//        public final boolean compareAndSet(int expect, int update)
//        如果这个值是期望的值,那么则更新为指定的值。
        System.out.println(atomicInteger.compareAndSet(5,20));
        System.out.println(atomicInteger.get());
        System.out.println(atomicInteger.compareAndSet(5,20));
        System.out.println(atomicInteger.get());
    }
}

分析:java.util.concurrent.atomic.AtomicInteger#getAndIncrement()

//java.util.concurrent.atomic.AtomicInteger#getAndIncrement
//unsafe可以直接操作内存
public final int getAndIncrement() {
    //valueOffset 当前这个对象的值的内存地址偏移值
    return unsafe.getAndAddInt(this, valueOffset, 1);
}
//sun.misc.Unsafe#getAndAddInt
public final int getAndAddInt(Object var1, long var2, int var4) {
    int var5;
    do {
        //var = 获得当前对象的内存地址中的值
        var5 = this.getIntVolatile(var1, var2);
        //compareAndSwapInt 比较并交换
        //比较当前的值,var1对象的var2地址中的值是不是var5,如果是则更新为var5+1
    } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
    return var5;
}

cas小结

  1. 循环开销很大
  2. 内存操作,每次只能保证一个共享变量的原子性
  3. 可能会出现ABA问题。

自旋锁:

package com.ruyidd.lock;

import java.util.concurrent.atomic.AtomicReference;

/**
 * @author: tianxc
 * @date: 2020-03-09 23:37
 * @desc:
 */
public class MyLock {
//锁线程
    //AtomicReference 默认是null
    //AtomicInteger 默认是0

    AtomicReference<Thread> atomicReference = new AtomicReference<>();

    public void lock(){
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName()+"===>get lock");
        //上锁自旋
        while (!atomicReference.compareAndSet(null,thread)){

        }

    }

    public void unlock(){
        Thread thread = Thread.currentThread();

        atomicReference.compareAndSet(thread,null);
        System.out.println(thread.getName()+"===>unlock");
    }
}


public static void main(String[] args) {
        MyLock lock = new MyLock();
        new Thread(()->{
            lock.lock();
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        },"T1").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(()->{
            lock.lock();
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        },"T2").start();
    }

JUC三

标签:null   编译   valueof   cas   变量   cti   thread   mis   public   

原文地址:https://www.cnblogs.com/tianxc/p/12455116.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!