• juc 并发编程学习笔记


    JUC

    以下学习笔记均来自视频资料https://www.bilibili.com/video/BV1B7411L7tE

    1.什么是juc

    java.util 工具包 包 分类

    业务:普通的线程代码 Thread

    Runnable:没有返回值,效率相比如Callable相对较低!

    2.线程和进程

    线程 进程 如果不能用一句话说出来的技术,不扎实!

    进程:一个进程往往可以包含多个线程,至少包含一个!

    java默认有几个线程? 2个 mian gc

    线程:对于java而言.Thread Runnable Callable

    java真的可以开启线程? 不能

        public synchronized void start() {
            /**
             * This method is not invoked for the main method thread or "system"
             * group threads created/set up by the VM. Any new functionality added
             * to this method in the future may have to also be added to the VM.
             *
             * A zero status value corresponds to state "NEW".
             */
            if (threadStatus != 0)
                throw new IllegalThreadStateException();
    
            /* Notify the group that this thread is about to be started
             * so that it can be added to the group's list of threads
             * and the group's unstarted count can be decremented. */
            group.add(this);
    
            boolean started = false;
            try {
                start0();
                started = true;
            } finally {
                try {
                    if (!started) {
                        group.threadStartFailed(this);
                    }
                } catch (Throwable ignore) {
                    /* do nothing. If start0 threw a Throwable then
                      it will be passed up the call stack */
                }
            }
        }
    //本地方法,底层的C++,java无法直接操作硬件
        private native void start0();
    

    并发 并行

    并发编程:并发 并行

    并发(多线程操作同一个资源)

    • CPU一核 模拟出来多个线程

    并行(多个人一起行走)

    • CPU多核,多个线程可以同时执行;线程池
        public static void main(String[] args) {
            //获取cpu的核数
            //cpu密集型  io密集型
      System.out.println(Runtime.getRuntime().availableProcessors());
        }
    

    并发编程的本质:充分利用CPU的资源

    线程有几个状态(6个)

    public enum State {
    		//新生
            NEW,
    
           	//运行
            RUNNABLE,
    
            //阻塞
            BLOCKED,
    
            //等待  死死的等
            WAITING,
    		//超时等待
            TIMED_WAITING,
    
            //终止
            TERMINATED;
        }
    

    wait.sleep区别

    1.来自不同的类

    wait=>Object

    sleep=>Thread

    2.关于锁的释放

    wait 释放锁

    sleep 抱着锁睡觉

    3.使用的范围不同

    wait 必须在同步代码块使用

    sleep 可以在任何地方使用

    4.是否需要捕获异常

    wait 不需要

    sleep 必须要捕获异常

    3.Lock锁

    传统 Synchronized

    
    //真正的多线程开发,公司中的开发  降低耦合性
        //线程就是一个单独的资源类,没有任何附属的操作
        //1.属性 方法
    public class SaleTicketDemo01 {
        public static void main(String[] args) {
            Ticket ticket = new Ticket();
            //函数式接口
            new Thread(()->{
                for (int i = 0; i < 60; i++) {
                 ticket.sale();
                } 
            },"a").start();
            new Thread(()->{
                for (int i = 0; i < 60; i++) {
                    ticket.sale();
                } 
            },"b").start();
            new Thread(()->{
                for (int i = 0; i < 60; i++) {
                    ticket.sale();
                } 
            },"c").start();
           
            
        }
        
    }
    
    //资源类OOP
    class Ticket{
        //属性 方法
        private int number = 50;
        
        //买票的方式
        public synchronized void sale(){
            if(number > 0){
                System.out.println(Thread.currentThread().getName() + number--);
                System.out.println("剩余"+number);
            }
        }
    }
    
    

    lock

    
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class SaleTicketDemo02 {
        public static void main(String[] args) {
            Ticket2 ticket = new Ticket2();
            new Thread(()->{
                for (int i = 0; i < 60; i++) {
                    ticket.sale();
                }
            },"a").start();
            new Thread(()->{
                for (int i = 0; i < 60; i++) {
                    ticket.sale();
                }
            },"b").start();
            new Thread(()->{
                for (int i = 0; i < 60; i++) 
                    ticket.sale();
                }
            },"c").start();
    
        }
    }
    
    
    //资源类OOP
    class Ticket2{
        //属性 方法
        private int number = 50;
    
        Lock lock = new ReentrantLock();
        
        //买票的方式
        public void sale(){
            lock.lock();//加锁
            try {
                if(number > 0){
                    System.out.println(Thread.currentThread().getName() + number--);
                    System.out.println("剩余"+number);
                }
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                lock.unlock();//解锁
            }
            
        }
    }
    
    

    公平锁:十分公平 可以先来后到

    非公平锁:十分不公平锁 可以插队(默认)

    synchronized 和 lock区别

    1. synchronized 内置的java关键字,lock是一个java类
    2. synchronized 无法判断获取锁的状态,Lock 可以判断是否获取到了锁
    3. synchronized 会自动释放锁 lock必须要手动释放锁! 如果不释放锁 死锁
    4. synchronized 线程1(获得锁,阻塞)线程2(等待 一直等);lock不一定会一直等下去
    5. synchronized 可重入锁不可以中断的,非公平;lock 可重锁,可以判断锁 非公平(可以自己设置)
    6. synchronized 适合锁少量的代码同步问题,lock 适合锁大量的同步代码

    锁是什么 如何判断锁的是谁!

    4.生产者和消费者问题

    面试笔试:单例模式 生产者消费者 排序算法 死锁

    生产者消费者问题 synchronized

    
    //线程之间的通信问题:生产者和消费者问题!   等待唤醒  通知唤醒
        //线程交替执行  A B 操作同一个变量  num = 0
        //A num + 1
        //B num - 1
    public class A {
    
        public static void main(String[] args) {
            Data data = new Data();
            
            new Thread(()->{
                for (int i = 0; i < 20; i++) {
                    try {
                        data.increment();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"a").start();
    
    
            new Thread(()->{
                for (int i = 0; i < 20; i++) {
                    try {
                        data.decrement();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"b").start();
        }
    }
    
    //资源类
    //等待   业务  通知
    class Data{
        private int num = 0;
        
        //+1
        public synchronized void increment() throws InterruptedException {
            if(num != 0){
                // 等待
                this.wait();
            }
            num++;
            System.out.println(Thread.currentThread().getName() + "=>"+num);
            //通知其他线程  我干完了
            this.notifyAll();
        }
        
        
        //-1
        public synchronized void decrement() throws InterruptedException {
            if(num == 0){
                this.wait();
            }
            num--;
            System.out.println(Thread.currentThread().getName() + "=>"+num);
            //通知其他线程  我干完了
            this.notifyAll();
        }
    }
    

    四个线程的话 会出现 虚假唤醒

    if改为while判断

    
    //线程之间的通信问题:生产者和消费者问题!   等待唤醒  通知唤醒
        //线程交替执行  A B 操作同一个变量  num = 0
        //A num + 1
        //B num - 1
    public class A {
    
        public static void main(String[] args) {
            Data data = new Data();
            
            new Thread(()->{
                for (int i = 0; i < 20; i++) {
                    try {
                        data.increment();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"a").start();
    
    
            new Thread(()->{
                for (int i = 0; i < 20; i++) {
                    try {
                        data.decrement();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"b").start();
        }
    }
    
    //资源类
    //等待   业务  通知
    class Data{
        private int num = 0;
        
        //+1
        public synchronized void increment() throws InterruptedException {
            while (num != 0){
                // 等待
                this.wait();
            }
            num++;
            System.out.println(Thread.currentThread().getName() + "=>"+num);
            //通知其他线程  我干完了
            this.notifyAll();
        }
        
        
        //-1
        public synchronized void decrement() throws InterruptedException {
            while (num == 0){
                this.wait();
            }
            num--;
            System.out.println(Thread.currentThread().getName() + "=>"+num);
            //通知其他线程  我干完了
            this.notifyAll();
        }
    }
    

    juc版的生产者和消费者问题 (此时结果是随机的)

    
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class B { 
        
        public static void main(String[] args) {
            Data2 data = new Data2();
        
            new Thread(()->{
                for (int i = 0; i < 20; i++) {
                    try {
                        data.increment();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"a").start();
        
        
            new Thread(()->{
                for (int i = 0; i < 20; i++) {
                    try {
                        data.decrement();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"b").start();
    
            new Thread(()->{
                for (int i = 0; i < 20; i++) {
                    try {
                        data.decrement();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"c").start();
    
    
            new Thread(()->{
                for (int i = 0; i < 20; i++) {
                    try {
                        data.decrement();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"d").start();
        }
    }
    
    //资源类
    //等待   业务  通知
    class Data2{
        private int num = 0;
        
        Lock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        
        //+1
        public void increment() throws InterruptedException {
            
            lock.lock();
            try {
                while (num != 0){
                    // 等待
                    condition.await();
                }
                num++;
                System.out.println(Thread.currentThread().getName() + "=>"+num);
                //通知其他线程  我干完了
                condition.signalAll();
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }
    
    
        //-1
        public void decrement() throws InterruptedException {
            lock.lock();
            try{
                while (num == 0){
                    condition.await();
                }
                num--;
                System.out.println(Thread.currentThread().getName() + "=>"+num);
                //通知其他线程  我干完了
                condition.signalAll();
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }
    }
    

    Condition实现精准唤醒通知

    
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    //a->b->c
    public class C {
        public static void main(String[] args) {
            Data3 data3 = new Data3();
            new Thread(()->{
                for (int i = 0; i < 20; i++) {
                    data3.printA();
                }
            },"a").start();
            new Thread(()->{
                for (int i = 0; i < 20; i++) {
                    data3.printB();
                }
            },"b").start();
            new Thread(()->{
                for (int i = 0; i < 20; i++) {
                    data3.printC();
                }
            },"c").start();
        }
    }
    
    class Data3{
        private Lock lock = new ReentrantLock();
        private Condition condition1 = lock.newCondition();
        private Condition condition2 = lock.newCondition();
        private Condition condition3 = lock.newCondition();
     
        
        int num = 1;
        public void printA(){
            lock.lock();
            try {
                while (num != 1){
                    // 等待
                    condition1.await();
                }
                num = 2;
                System.out.println(Thread.currentThread().getName() + "=>"+num);
                //通知其他线程  我干完了
                condition2.signal();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
        public void printB(){
            lock.lock();
            try {
                while (num != 2){
                    // 等待
                    condition2.await();
                }
                num = 3;
                System.out.println(Thread.currentThread().getName() + "=>"+num);
                //通知其他线程  我干完了
                condition3.signal();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
        public void printC(){
            lock.lock();
            try {
                while (num != 3){
                    // 等待
                    condition3.await();
                }
                num = 1;
                System.out.println(Thread.currentThread().getName() + "=>"+num);
                //通知其他线程  我干完了
                condition1.signal();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }
    
    

    5. 8锁现象

    锁是什么 如何判断锁的是谁!

    
    import java.util.concurrent.TimeUnit;
    
    //关于锁的8个问题
    //1.标准情况下,两个线程先打印sendSms还是call   1sendSms  2call
    //2.延迟1秒sendSms,两个线程先打印sendSms还是call  1sendSms  2call
    public class Test01 {
        public static void main(String[] args) throws InterruptedException {
            Phone phone = new Phone();
            new Thread(()-> {
                try {
                    phone.sendSms();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            },"A").start();
            TimeUnit.SECONDS.sleep(1);
            new Thread(()-> phone.call(),"B").start();
        }
        
    }
    
    
    class Phone{
        
        //synchronized 锁的对象是方法的调用者
        //两个方法用的是同一个锁,谁先拿到谁先执行
        
        public synchronized void sendSms() throws InterruptedException {
            TimeUnit.SECONDS.sleep(1);
            System.out.println("sendSms");
        }
    
    
        public synchronized void call(){
            System.out.println("call");
        }
    }
    
    
    import java.util.concurrent.TimeUnit;
    
    //关于锁的8个问题
    //3.标准情况下增加普通方法,两个线程先打印sendSms还是hello  1 hello  2sendSms
    //4.延迟1秒sendSms,两个线程先打印sendSms还是call
    public class Test02 {
        public static void main(String[] args) throws InterruptedException {
            Phone2 phone = new Phone2();
            new Thread(()-> {
                try {
                    phone.sendSms();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            },"A").start();
            
            
            TimeUnit.SECONDS.sleep(1);
            
            new Thread(()-> phone.hello(),"B").start();
        }
        
    }
    
    
    class Phone2{
        
        //synchronized 锁的对象是方法的调用者
        //两个方法用的是同一个锁,谁先拿到谁先执行
        
        public synchronized void sendSms() throws InterruptedException {
            TimeUnit.SECONDS.sleep(4);
            System.out.println("sendSms");
        }
    
    
        public synchronized void call(){
            System.out.println("call");
        }
        
        //没有锁  不是同步方法不受锁的影响
        public void hello(){
            System.out.println("hello");
        }
    }
    
    
    
    import java.util.concurrent.TimeUnit;
    
    import static com.mj.juc.lock8.Phone3.sendSms;
    
    //5.增加两个静态的同步方法,只有一个对象  1sendSms  2call
    //6.两个对象  增加两个静态的同步方法,只有一个对象  1sendSms  2call
    public class Test03 {
        public static void main(String[] args) throws InterruptedException {
            //两个对象的class类模板之后一个  static 锁的是class
            Phone3 phone1 = new Phone3();
            Phone3 phone2 = new Phone3();
            
            new Thread(()-> {
                try {
                    phone1.sendSms();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            },"A").start();
            TimeUnit.SECONDS.sleep(1);
            new Thread(()-> phone2.call(),"B").start();
        }
    
    }
    
    
    class Phone3{
    
        //synchronized 锁的对象是方法的调用者
        //static 静态方法
        //类一加载就有了  class 模板
        public static synchronized void sendSms() throws InterruptedException {
            TimeUnit.SECONDS.sleep(1);
            System.out.println("sendSms");
        }
    
    
        public static synchronized void call(){
            System.out.println("call");
        }
    }
    
    
    
    import java.util.concurrent.TimeUnit;
    
    //7. 一个静态同步方法 一个普通的同步方法, 一个对象 call sendSms
    //8. 一个静态同步方法 一个普通的同步方法, 两个对象 call sendSms
    
    public class Test04 {
        public static void main(String[] args) throws InterruptedException {
            //两个对象的class类模板之后一个  static 锁的是class
            Phone4 phone1 = new Phone4();
            Phone4 phone2 = new Phone4();
    
            new Thread(()-> {
                try {
                    phone1.sendSms();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            },"A").start();
            TimeUnit.SECONDS.sleep(1);
            new Thread(()-> phone2.call(),"B").start();
        }
    
    }
    
    
    class Phone4{
    
        //synchronized 锁的对象是方法的调用者
        //static 静态方法
        //类一加载就有了  class 模板
        public static synchronized void sendSms() throws InterruptedException {
            TimeUnit.SECONDS.sleep(4);
            System.out.println("sendSms");
        }
    
    
    //    锁的对象是方法的调用者
        public synchronized void call(){
            System.out.println("call");
        }
    }
    

    小结

    new this 具体的一个对象

    static Class 唯一的一个模板

    6.集合类不安全

    List 不安全

    
    
    import java.util.*;
    import java.util.concurrent.CopyOnWriteArrayList;
    
    //java.util.ConcurrentModificationException  并发修改异常!
    
    public class ListTest {
    
        public static void main(String[] args) {
            //并发下ArrayList 不安全
    
            /**
             * 解决方案
             * 1.List<String> list = new Vector<>();
             * 2.List<String> list = Collections.synchronizedList(new ArrayList<>());
             * 3.List<String> list = new CopyOnWriteArrayList<>(); (写入时复制  COW思想)
             
             
             CopyOnWriteArrayList和vector  synchronized效率一定会慢
             */
            List<String> list = new CopyOnWriteArrayList<>();
    
            for (int i = 0; i < 10; i++) {
                new Thread(()->{
                    list.add(UUID.randomUUID().toString());
                    System.out.println(list);
                }).start();
                
            }
            
        }
    }
    
    

    Set不安全

    
    import java.util.Collections;
    import java.util.HashSet;
    import java.util.Set;
    import java.util.UUID;
    import java.util.concurrent.CopyOnWriteArraySet;
    
    //1. Set<String> set = Collections.synchronizedSet(new HashSet<>());
    //2. Set<String> set = new CopyOnWriteArraySet<>();
    public class SetTest {
        public static void main(String[] args) {
    
    //        Set<String> set = new HashSet<>();
    
            //Set<String> set = Collections.synchronizedSet(new HashSet<>());
            Set<String> set = new CopyOnWriteArraySet<>();
            for (int i = 0; i < 1000; i++) {
                new Thread(()->{
                    set.add(UUID.randomUUID().toString());
                    System.out.println(set);
                },String.valueOf(i)).start();
            }
    
        }
    }
    
    

    hashSet 是什么?

    public HashSet() {
            map = new HashMap<>();
        }
    
    //add set 本质就是map
    public boolean add(E e) {
            return map.put(e, PRESENT)==null;
        }
    
    private static final Object PRESENT = new Object();//不变的值
    

    Map 不安全

    
    import java.util.HashMap;
    import java.util.Map;
    import java.util.UUID;
    import java.util.concurrent.ConcurrentHashMap;
    
    public class MapTest {
    
        public static void main(String[] args) {
    
            //map  是这样用的吗?
            // 默认等价于什么? new HashMap<>(16,0.75); 加载因子  初始化容量
    //        HashMap<String, String> map = new HashMap<>();
            Map<String, String> map = new ConcurrentHashMap<>();
            for (int i = 1; i < 30; i++) {
                new Thread(()->{
                    map.put(Thread.currentThread().getName(), UUID.randomUUID().toString());
                    System.out.println(map);
                },String.valueOf(i)).start();
            }
            
        }
        
    }
    
    

    7. Callable(简单)

    1. 可以有返回值
    2. 可以抛出异常
    3. 方法不同
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.FutureTask;
    
    public class CallableTest {
    
        public static void main(String[] args) throws ExecutionException, InterruptedException {
    
    
            MyThread myThread = new MyThread();
            //适配类
            FutureTask futureTask = new FutureTask<>(myThread);
            new Thread(futureTask,"A").start();
            Integer o = (Integer)futureTask.get();
            System.out.println("call()" + o);
        }
    }
    
    
    class MyThread implements Callable<Integer> {
    
    
        @Override
        public Integer call() throws Exception {
            System.out.println("call()");
            return 123;
        }
    }
    
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.FutureTask;
    
    public class CallableTest {
    
        public static void main(String[] args) throws ExecutionException, InterruptedException {
    
    
            MyThread myThread = new MyThread();
            //适配类
            FutureTask futureTask = new FutureTask<>(myThread);
            new Thread(futureTask,"A").start();
            new Thread(futureTask,"B").start();//结果会被缓存
            //这个get,方法可能会产生阻塞  把他放到最后
            Integer o = (Integer)futureTask.get();
            //或者使用异步通信来处理!
            System.out.println("call()" + o);
        }
    }
    
    
    class MyThread implements Callable<Integer> {
    
    
        @Override
        public Integer call() throws Exception {
            System.out.println("call()");
            return 123;
        }
    }
    

    注意 有缓存 提高效率但可能造成阻塞

    8.常用的辅助类

    8.1 CountDownLatch

    
    
    import java.util.concurrent.CountDownLatch;
    
    //减法计数器
    public class CountDownLatchDemo {
        public static void main(String[] args) throws InterruptedException {
            
            //必须要执行任务的时候再使用
            CountDownLatch countDownLatch = new CountDownLatch(6);
            for (int i = 1; i <= 6; i++) {
                new Thread(()->{
                    System.out.println(Thread.currentThread().getName());
                    countDownLatch.countDown();
                }).start();
            }
            //等待计数器归零,然后向下执行
            countDownLatch.await();
            
            System.out.println("shutdown");
        }
        
    }
    
    

    原理:

    countDownLatch.countDown(); //数量-1
    
    countDownLatch.await();//等待计数器归零,然后向下执行
    每次有线程调用countDown() 数量-1 假设计数器变为0,countDownLatch.await();就会被唤醒,继续执行!!!
    

    8.2 CycliBarrier

    
    
    import java.util.concurrent.BrokenBarrierException;
    import java.util.concurrent.CyclicBarrier;
    //加法计数器
    public class CycliBarrierDemo {
        //
    
        public static void main(String[] args) {
    
    
            CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{
                System.out.println("召唤神龙");
            });
    
            for (int i = 1; i <= 7; i++) {
                int finalI = i;
                new Thread(()->{
                    System.out.println(Thread.currentThread().getName() + "收集了" + finalI);
                    try {
                        cyclicBarrier.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                }).start();
            }
        }
        
    }
    
    

    8.3 Semaphore 信号量

    
    
    import java.util.concurrent.Semaphore;
    import java.util.concurrent.TimeUnit;
    
    public class SemaphoneDemo {
        public static void main(String[] args) {
    
            // 线程数量:停车位   限流
            Semaphore semaphore = new Semaphore(3);
    
            for (int i = 1; i <= 6; i++) {
                new Thread(()->{
                    //acquire() 得到
                    try {
                        semaphore.acquire();
                        System.out.println(Thread.currentThread().getName() + "抢到了车位");
                        TimeUnit.SECONDS.sleep(2);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }finally {
                        semaphore.release();
                    }
                },String.valueOf(i)).start();
            }
            
        }
    }
    

    原理:

    semaphore.acquire(); 获得 ,假设如果已经满了,等待 等待被释放

    semaphore.release(); 释放,会将当前的信号量释放+1,然后唤醒等待的线程

    作用: 多个共享资源互斥的使用!并发限流.控制最大的线程数!

    9.读写锁

    
    
    import java.util.HashMap;
    import java.util.Map;
    import java.util.concurrent.locks.ReadWriteLock;
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    
    /**
     * 独占锁(写锁) 一次只能被一个线程占有
     * 共享锁(读锁) 多个线程可以同时占有
     * 
     * 读读 可以共享
     * 读写 不能共享
     * 写写 不能共享
     */
    
    public class ReadWriteLockDemo {
    
        public static void main(String[] args) {
            MyCacheLock myCache = new MyCacheLock();
            
            for (int i = 0; i < 6; i++) {
                int finalI = i;
                new Thread(()->{
                    myCache.put(finalI +"", finalI);
                }).start();
            }
    
    
            for (int i = 0; i < 6; i++) {
                int finalI = i;
                new Thread(()->{
                    myCache.get(finalI +"");
                }).start();
            }
            
        }
    }
    
    
    /**
     * 自定义缓存
     */
    class MyCache{
        
        private volatile Map<String,Object> map = new HashMap<>();
        
        //存  写
        public void put(String key,Object value){
            System.out.println(Thread.currentThread().getName() + "写ok" +key);
            map.put(key,value);
            System.out.println(Thread.currentThread().getName() + "写ok");
        }
        
        //读
        public void get(String key){
            System.out.println(Thread.currentThread().getName() + "读ok" +key);
            Object o = map.get(key);
            System.out.println(Thread.currentThread().getName() + "读ok");
        }
    
    }
    /**
     * 自定义缓存 (带锁)
     */
    class MyCacheLock{
    
        private volatile Map<String,Object> map = new HashMap<>();
        private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    
        //存  写
        public void put(String key,Object value){
            readWriteLock.writeLock().lock();
            try {
                System.out.println(Thread.currentThread().getName() + "写ok" +key);
                map.put(key,value);
                System.out.println(Thread.currentThread().getName() + "写ok");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                readWriteLock.writeLock().unlock();
            }
           
        }
    
        //读
        public void get(String key){
            readWriteLock.readLock().lock();
            try {
                System.out.println(Thread.currentThread().getName() + "读ok" +key);
                Object o = map.get(key);
                System.out.println(Thread.currentThread().getName() + "读ok");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                readWriteLock.readLock().unlock();
            }
           
        }
    
    }
    

    10.阻塞队列

    BlockingQueue

    使用场景:多线程并发处理 线程池

    学会使用队列

    添加 移除

    四组API

    方式 抛出异常 不会抛出异常 阻塞 等待 超时等待
    添加 add() offer() put() offer(value,long,TimeUtil)
    移除 remove() poll() take() poll(long,TimeUtil)
    判断队列首 element peek
    1. 抛出异常
    /**
         * 抛出异常
         */
        
        public static void test1(){
            //队列的大小
            ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue<>(3);
            System.out.println(arrayBlockingQueue.add("a"));
            System.out.println(arrayBlockingQueue.add("b"));
            System.out.println(arrayBlockingQueue.add("c"));
            
            //抛出异常
            //java.lang.IllegalStateException: Queue full
    //        System.out.println(arrayBlockingQueue.add("d"));
    
            System.out.println("------------------------------");
            //抛出异常
            //java.util.NoSuchElementException
    //        System.out.println(arrayBlockingQueue.remove());
    //        System.out.println(arrayBlockingQueue.remove());
    //        System.out.println(arrayBlockingQueue.remove());
    //        System.out.println(arrayBlockingQueue.remove());
            
        }
    

    2.不会抛出异常

    /**
         * 有返回值 没有异常
         */
        public static void test2(){
            //队列的大小
            ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue<>(3);
            System.out.println(arrayBlockingQueue.offer("a"));
            System.out.println(arrayBlockingQueue.offer("b"));
            System.out.println(arrayBlockingQueue.offer("c"));
            
            //返回false
    //        System.out.println(arrayBlockingQueue.offer("d"));
    
            System.out.println(arrayBlockingQueue.poll());
            System.out.println(arrayBlockingQueue.poll());
            System.out.println(arrayBlockingQueue.poll());
            System.out.println(arrayBlockingQueue.poll());
            
        }
    

    3.阻塞 等待

    /**
         * 等待  阻塞(一直阻塞)
         */
        public static void test3() throws InterruptedException {
            ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue<>(3);
    
            arrayBlockingQueue.put("a");
            arrayBlockingQueue.put("b");
            arrayBlockingQueue.put("c");
            //没有位置会一直等待
    //        arrayBlockingQueue.put("d");  
            System.out.println(arrayBlockingQueue.take());
            System.out.println(arrayBlockingQueue.take());
            System.out.println(arrayBlockingQueue.take());
            //没有这个值 会一直阻塞
    //        System.out.println(arrayBlockingQueue.take());
            
        }
    

    4.超时等待

    /**
     * 等待  阻塞(超时)
     */
    public static void test4() throws InterruptedException {
        ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue<>(3);
    
        arrayBlockingQueue.offer("a");
        arrayBlockingQueue.offer("b");
        arrayBlockingQueue.offer("c");
        //如果超出时间还没有   等待2秒就退出
        arrayBlockingQueue.offer("d", 2,TimeUnit.SECONDS);
        
        
        System.out.println(arrayBlockingQueue.poll());
        System.out.println(arrayBlockingQueue.poll());
        System.out.println(arrayBlockingQueue.poll());
        //等待2秒就退出
        arrayBlockingQueue.poll(2,TimeUnit.SECONDS);
    }
    

    SynchronousQueue 同步队列

    没有容量

    进去一个元素 必须等待取出来之后,才能再往里面放一个元素 put take

    
    
    
    import java.util.concurrent.BlockingQueue;
    import java.util.concurrent.SynchronousQueue;
    import java.util.concurrent.TimeUnit;
    
    public class SynchronousQueueDemo {
        public static void main(String[] args) {
    
            BlockingQueue<String> synchronousQueue = new SynchronousQueue<>();
            
            new Thread(()->{
                try {
                    System.out.println(Thread.currentThread().getName() + "put 1");
                    synchronousQueue.put("1");
                    System.out.println(Thread.currentThread().getName() + "put 2");
                    synchronousQueue.put("2");
                    System.out.println(Thread.currentThread().getName() + "put 3");
                    synchronousQueue.put("3");
                } catch (InterruptedException e) {
                e.printStackTrace();
            }
            }).start();
    
            new Thread(()->{
                try {
                    TimeUnit.SECONDS.sleep(2);
                    System.out.println(Thread.currentThread().getName() + "get" + synchronousQueue.take());
                    TimeUnit.SECONDS.sleep(2);
                    System.out.println(Thread.currentThread().getName() + "get" + synchronousQueue.take());
                    TimeUnit.SECONDS.sleep(2);
                    System.out.println(Thread.currentThread().getName() + "get" + synchronousQueue.take());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
    

    11. 线程池(重点)

    线程池:三大方法 七大策略

    池化技术

    程序的运行,本质:占用系统的资源! 优化资源的使用! =>池化技术

    创建销毁 十分浪费资源

    池化技术:实现准备好一些资源,用来拿,用完还

    线程池的好处:

    1. 降低资源的消耗
    2. 提高响应的速度
    3. 方便管理

    线程复用 控制最大并发 管理线程

    三大方法

    
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    //Executors  工具类  3大方法
    public class Demo01 {
        public static void main(String[] args) {
            ExecutorService executorService = Executors.newSingleThreadExecutor();//单个线程
    //        ExecutorService executorService = Executors.newFixedThreadPool(5);//创建一个固定的线程池的大小
    //        ExecutorService executorService = Executors.newCachedThreadPool();//可伸缩的
    
    
            try {
                for (int i = 0; i < 100; i++) {
                    executorService.execute(()->{
                        System.out.println(Thread.currentThread().getName());
                    });
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                //线程池用完,程序结束 关闭线程池
                executorService.shutdown();
            }
        }
    }
    

    七大参数

    源码

    //1public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }
    //2
        public static ExecutorService newFixedThreadPool(int nThreads) {
            return new ThreadPoolExecutor(nThreads, nThreads,
                                          0L, TimeUnit.MILLISECONDS,
                                          new LinkedBlockingQueue<Runnable>());
        }
    
    
    //3
        public static ExecutorService newCachedThreadPool() {
            return new ThreadPoolExecutor(0, Integer.MAX_VALUE,//约等于21亿
                                          60L, TimeUnit.SECONDS,
                                          new SynchronousQueue<Runnable>());
        }
    
    
    //本质ThreadPoolExecutor
        public ThreadPoolExecutor(int corePoolSize,//核心线程池大小
                                  int maximumPoolSize,//最大核心线程池大小
                                  long keepAliveTime,//超时了没有人调用就会移除
                                  TimeUnit unit,//超时单位
                                  BlockingQueue<Runnable> workQueue,//阻塞队列
                                  ThreadFactory threadFactory,//线程工厂 创建线程的  一般不动
                                  RejectedExecutionHandler handler//拒绝策略) {
            if (corePoolSize < 0 ||
                maximumPoolSize <= 0 ||
                maximumPoolSize < corePoolSize ||
                keepAliveTime < 0)
                throw new IllegalArgumentException();
            if (workQueue == null || threadFactory == null || handler == null)
                throw new NullPointerException();
            this.corePoolSize = corePoolSize;
            this.maximumPoolSize = maximumPoolSize;
            this.workQueue = workQueue;
            this.keepAliveTime = unit.toNanos(keepAliveTime);
            this.threadFactory = threadFactory;
            this.handler = handler;
        }
    

    手动创建线程池

    
    import java.util.concurrent.*;
    
    //Executors  工具类  3大方法
    
    
    //java.util.concurrent.RejectedExecutionException   //银行满了  还有人进来,  不处理并[抛出异常
    
    public class Demo01 {
        public static void main(String[] args) {
            
            //阿里巴巴规范不推荐使用
    //        ExecutorService executorService = Executors.newSingleThreadExecutor();//单个线程
    //        ExecutorService executorService = Executors.newFixedThreadPool(5);//创建一个固定的线程池的大小
    //        ExecutorService executorService = Executors.newCachedThreadPool();//可伸缩的
    
    
    
            //自定义线程池 
            ExecutorService executorService = new ThreadPoolExecutor(
                    2,
                    5,
                    3,
                    TimeUnit.SECONDS,
                    new LinkedBlockingDeque<>(3),
                    Executors.defaultThreadFactory(),
    //                new ThreadPoolExecutor.AbortPolicy() //银行满了  还有人进来,  不处理并[抛出异常
    //                new ThreadPoolExecutor.CallerRunsPolicy()  //哪来的去哪里
    //                new ThreadPoolExecutor.DiscardPolicy()  //队列满了,丢掉任务,不会抛出异常
                    new ThreadPoolExecutor.DiscardOldestPolicy()  //队列满了,尝试去和最早的竞争  不会抛出异常
            );
            
    
    
            try {
                
                //最大承载:   deque + max
                //超过RejectedExecutionException
                for (int i = 0; i < 9; i++) {
                    executorService.execute(()->{
                        System.out.println(Thread.currentThread().getName());
                    });
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                //线程池用完,程序结束 关闭线程池
                executorService.shutdown();
            }
        }
    }
    

    小结和拓展

    线程池的最大线程数如何设置!

    了解:io 密集型 cpu密集型(调优)

    
    import java.util.concurrent.*;
    public class Demo01 {
        public static void main(String[] args) {
            //自定义最大线程到底改如何定义
            //1.CPU 密集型 集合,就是几  可以保持CPU的最高效率!
            //2.IO 密集型  判断程序中十分耗io的线程 要大于这个数
            
            //获取cpu核数
    //        Runtime.getRuntime().availableProcessors();
            //自定义线程池 
            ExecutorService executorService = new ThreadPoolExecutor(
                    2,
                    Runtime.getRuntime().availableProcessors(),
                    3,
                    TimeUnit.SECONDS,
                    new LinkedBlockingDeque<>(3),
                    Executors.defaultThreadFactory(),
    //                new ThreadPoolExecutor.AbortPolicy() //银行满了  还有人进来,  不处理并[抛出异常
    //                new ThreadPoolExecutor.CallerRunsPolicy()  //哪来的去哪里
    //                new ThreadPoolExecutor.DiscardPolicy()  //队列满了,丢掉任务,不会抛出异常
                    new ThreadPoolExecutor.DiscardOldestPolicy()  //队列满了,尝试去和最早的竞争  不会抛出异常
            );
            
    
    
            try {
                
                //最大承载:   deque + max
                //超过RejectedExecutionException
                for (int i = 0; i < 9; i++) {
                    executorService.execute(()->{
                        System.out.println(Thread.currentThread().getName());
                    });
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                //线程池用完,程序结束 关闭线程池
                executorService.shutdown();
            }
        }
    }
    
    

    12.四大函数式接口(必需掌握)

    新时代的程序员: lambad表达式 链式编程 函数式接口 stream流式计算

    函数式接口:只有一个方法的接口

    //例如
    @FunctionalInterface
    public interface Runnable {
        public abstract void run();
    }
    //超级多@FunctionalInterface
    //简化编程
    

    Function 函数型接口,有一个输入参数,有一个输出

    
    import java.util.function.Function;
    
    /**
     * Function  函数型接口,有一个输入参数,有一个输出
     * 只要是 函数型接口   可以用lambad表达式简化
     */
    public class Demo01 {
    
        public static void main(String[] args) {
    //        new Function<String,String>(){
    //
    //            @Override
    //            public String apply(String o) {
    //                return o;
    //            }
    //        };
            
            Function function = (str)-> str;
            System.out.println(function.apply("adsds"));
        }
    }
    

    Predicate 断定型接口 :有一个输入参数 返回值只能是布尔值

    
    
    import java.util.function.Predicate;
    
    public class Demo02 {
        public static void main(String[] args) {
    
    //        Predicate<String> predicate = new Predicate<String>() {
    //
    //            @Override
    //            public boolean test(String s) {
    //                return s.isEmpty();
    //            }
    //        };
    
    //        Predicate<String> predicate = String::isEmpty;
            Predicate<String> predicate = str->str.isEmpty();
    
            System.out.println(predicate.test(""));
        }
    }
    

    Consumer 消费型接口 只有输入没有返回值

    
    
    import java.util.function.Consumer;
    //Consumer  消费型接口  只有输入没有返回值
    public class Demo03 {
    
        public static void main(String[] args) {
    //        Consumer<String> consumer = new Consumer<String>() {
    //
    //            @Override
    //            public void accept(String s) {
    //                System.out.println(s);
    //            }
    //        };
    
            Consumer<String> consumer = (str)-> System.out.println(str);
            
            consumer.accept("ss");
        }
    }
    

    Supplier 供给型接口 没有参数 只有返回值

    
    
    import java.util.function.Supplier;
    
    /**
     * Supplier  没有参数  只有返回值
     */
    public class Demo04 {
    
    
        public static void main(String[] args) {
    //        Supplier<String> supplier = new Supplier<String>() {
    //
    //            @Override
    //            public String get() {
    //                return "123456";
    //  
            
            Supplier<String> supplier = ()-> "10123";
            
            System.out.println(supplier.get());
        }
    }
    

    13.Stream流式计算

    什么是Stream流式计算

    大数据:存储+计算

    集合 mysql本质都是存储东西;

    计算都应该交给流.

    
    import java.util.Arrays;
    import java.util.List;
    
    /**
     * 一行代码实现
     * 现有5个用户筛选
     * 1.ID必须是偶数
     * 2.年龄必须大于23岁
     * 3.用户名字转为大写字母
     * 4.用户名字倒序
     * 5.只输出一个用户
     */
    public class Test {
        public static void main(String[] args) {
            User user1 = new User(1, "a", 21);
            User user2 = new User(2, "b", 25);
            User user3 = new User(3, "c", 23);
            User user4 = new User(4, "d", 24);
            User user5 = new User(5, "e", 25);
            //集合是存储的
            List<User> list = Arrays.asList(user1, user2, user3, user4, user5);
            
            //lambad  链式编程  函数式接口 Stream流式计算
            list.stream()
                    .filter(user -> {return user.getId()%2 == 0;})
                    .filter(user -> {return user.getAge()>23;})
                    .map(user -> {return user.getName().toUpperCase();})
                    .sorted((u1,u2)->{return u2.compareTo(u1);})
                    .limit(1)
                    .forEach(System.out::println);
    
        }
    }
    

    14.ForkJoin

    什么是ForkJoin

    forkJoin 在jdk1.7就出现了 并行执行任务

    ForkJoin特点:工作窃取

    这个里面维护的都是双端队列

    ForkJoin的使用

    
    import java.util.concurrent.RecursiveTask;
    
    /**
     * 求和计算的任务
     * @author Administrator
     * 1.forkjoin 通过他来执行
     * 2.计算任务 forkjoinPool.execute(ForkJoinTask task)
     * 3.计算类要继承 ForkJoinTask
     */
    public class ForkJoinDemo extends RecursiveTask<Long> {
    
        Long start;
        Long end;
        
        //临界值
        Long temp = 10000L;
    
        public ForkJoinDemo(long start, long end) {
            this.start = start;
            this.end = end;
        }
        
    
        @Override
        protected Long compute() {
            Long sum = 0L;
            if((end-start) < temp){
                for(Long lo = start; lo < end; lo ++ ){
                    sum += lo;
                }
            }else{
                //分支合并计算 forkjoin
                long middle = (start + end) / 2;//中间值
                ForkJoinDemo task1 = new ForkJoinDemo(start, middle);
                task1.fork();//拆分任务,把任务压入线程队列
                ForkJoinDemo task2 = new ForkJoinDemo(middle+1, end);
                task2.fork();
                sum = task1.join() + task2.join();
            }
            return sum;
        }
    }
    
    
    
    
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ForkJoinPool;
    import java.util.concurrent.ForkJoinTask;
    import java.util.stream.LongStream;
    
    public class Test {
        public static void main(String[] args) throws ExecutionException, InterruptedException {
            //时间  5251
    //        test1();
            
            //时间 3772
    //        test2();
            
            //时间  895
            test3();
        }
        
        public static void test1(){
            long start = System.currentTimeMillis();
            long sum = 0L;
            for(Long lo = 0L; lo < 10_0000_0000; lo ++ ){
                sum += lo;
            }
            long end = System.currentTimeMillis();
            System.out.println("sum=" + sum + "时间: " +(end - start));
        }
    
    
        //forkjoin
        public static void test2() throws ExecutionException, InterruptedException {
            long start = System.currentTimeMillis();
            ForkJoinPool forkJoinPool = new ForkJoinPool();
            ForkJoinTask<Long> forkJoinDemo = new ForkJoinDemo(0L,10_0000_0000L);
            ForkJoinTask<Long> submit = forkJoinPool.submit(forkJoinDemo);
            Long aLong = submit.get();
            long end = System.currentTimeMillis();
            System.out.println("sum=" + aLong + "时间: " +(end - start));
        }
    
        //stream流计算
        public static void test3(){
            long start = System.currentTimeMillis();
    
            long sum = LongStream.rangeClosed(0L, 10_0000_0000L).parallel().reduce(0, Long::sum);
    
            long end = System.currentTimeMillis();
            System.out.println("sum=" + sum + "时间: " +(end - start));
        }
        
    }
    
    

    15. 异步回调

    Future 设计的初衷: 对将来的某个事例的结果进行建模

    
    import java.util.concurrent.CompletableFuture;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.TimeUnit;
    
    /**
     * 异步调用 CompletableFuture
     * 异步执行
     * 成功回调
     * 失败回调
     */
    public class Demo01 {
    
        public static void main(String[] args) throws ExecutionException, InterruptedException {
            //没有返回值的异步回调   runAsync
            /*CompletableFuture<Void> voidCompletableFuture = CompletableFuture.runAsync(() -> {
                try {
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("-------");
            });*/
    
    
            //有返回值的异步回调  supplyAsync
            CompletableFuture<Integer> voidCompletableFuture = CompletableFuture.supplyAsync(() -> {
                System.out.println(Thread.currentThread().getName() + "supplyAsync");
                int i = 10/0;
                return 2021;
            });
    
            System.out.println("111111");
            voidCompletableFuture.whenComplete((t,u)->{
                System.out.println("t----------------->" + t);//正常的返回结果
                System.out.println("u----------------->" + u);//错误信息  java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
            }).exceptionally((e)->{
                System.out.println(e.getMessage() );//错误信息 java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
                return 233;
            });
        }
        
    }
    

    16.JMM

    volatile的理解

    Volatile 是 java 虚拟机提供轻量级的同步机制

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

    什么是JMM

    JMM是java内存模型,不存在的东西

    关于JMM的一下同步的约定:

    1. 线程解锁前,必须要把共享变量立刻刷回主存;
    2. 线程加锁前,必须读取主存中的最新值到工作内存中!
    3. 加锁和解锁是同一把锁
      线程/工作内存/主内存 三者的关系

    一、每个线程都有一个独立的工作内存,用于存储线程私有的数据

    二、Java内存模型中规定所有变量都存储在主内存,主内存是共享内存区域,所有线程都可以访问

    三、线程对变量的操作(读取赋值等)必须在工作内存中进行。(线程安全问题的根本原因)

    (1)首先要将变量从主内存拷贝的自己的工作内存空间

    (2)然后对变量进行操作,操作完成后再将变量写回主内存

    (3)不能直接操作主内存中的变量,工作内存中存储着主内存中的变量副本拷贝

    (4)因此不同的线程间无法访问对方的工作内存,线程间的通信(传值)必须通过主内存来完成。

    主内存和工作内存

    一、主内存是在运行期间所有变量的存放区域,当工作内存是运行期间中某一线程独立私有的内存存放区域

    二、线程间无法访问对方的工作内存空间,都是通过主内存交换来实现

    三、主内存的变量在工作内存中的值是复制过去的副本,读写完成后刷新主内存,这意味着主内存如果发生了改变,工作内存并无法获得最新的结果

    四、多个线程对一个共享变量进行修改时,都是对自己工作内存的副本进行操作,相互不可见。主内存最后得到的结果是不可预知的

    8种操作:

    关于主内存与工作内存之间的交互协议,即一个变量如何从主内存拷贝到工作内存。如何从工作内存同步到主内存中的实现细节。java内存模型定义了8种操作来完成。这8种操作每一种都是原子操作。8种操作如下:

    • lock(锁定):作用于主内存,它把一个变量标记为一条线程独占状态;
    • read(读取):作用于主内存,它把变量值从主内存传送到线程的工作内存中,以便随后的load动作使用;
    • load(载入):作用于工作内存,它把read操作的值放入工作内存中的变量副本中;
    • use(使用):作用于工作内存,它把工作内存中的值传递给执行引擎,每当虚拟机遇到一个需要使用这个变量的指令时候,将会执行这个动作;
    • assign(赋值):作用于工作内存,它把从执行引擎获取的值赋值给工作内存中的变量,每当虚拟机遇到一个给变量赋值的指令时候,执行该操作;
    • store(存储):作用于工作内存,它把工作内存中的一个变量传送给主内存中,以备随后的write操作使用;
    • write(写入):作用于主内存,它把store传送值放到主内存中的变量中。
    • unlock(解锁):作用于主内存,它将一个处于锁定状态的变量释放出来,释放后的变量才能够被其他线程锁定;

    Java内存模型还规定了执行上述8种基本操作时必须满足如下规则:

    (1)不允许read和load、store和write操作之一单独出现(即不允许一个变量从主存读取了但是工作内存不接受,或者从工作内存发起会写了但是主存不接受的情况),以上两个操作必须按顺序执行,但没有保证必须连续执行,也就是说,read与load之间、store与write之间是可插入其他指令的。

    (2)不允许一个线程丢弃它的最近的assign操作,即变量在工作内存中改变了之后必须把该变化同步回主内存。

    (3)不允许一个线程无原因地(没有发生过任何assign操作)把数据从线程的工作内存同步回主内存中。

    (4)一个新的变量只能从主内存中“诞生”,不允许在工作内存中直接使用一个未被初始化(load或assign)的变量,换句话说就是对一个变量实施use和store操作之前,必须先执行过了assign和load操作。

    (5)一个变量在同一个时刻只允许一条线程对其执行lock操作,但lock操作可以被同一个条线程重复执行多次,多次执行lock后,只有执行相同次数的unlock操作,变量才会被解锁。

    (6)如果对一个变量执行lock操作,将会清空工作内存中此变量的值,在执行引擎使用这个变量前,需要重新执行load或assign操作初始化变量的值。

    (7)如果一个变量实现没有被lock操作锁定,则不允许对它执行unlock操作,也不允许去unlock一个被其他线程锁定的变量。

    (8)对一个变量执行unlock操作之前,必须先把此变量同步回主内存(执行store和write操作)。

    17.volatile

    1.可见性

    package com.mj.juc.jmm;
    
    
    public class JMMDemo {
        private static int num = 0;
    
        public static void main(String[] args) {//main 线程
    
    
            //线程a
            new Thread(()->{
                while (num == 0){
    //                System.out.println(num + Thread.currentThread().getName());
                }
    //            System.out.println(num + Thread.currentThread().getName());
            },"a").start();
    
    
            new Thread(()->{
    //            System.out.println("修改值");
                try {
                   TimeUnit.SECONDS.sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
      
                }            
                num = 1;
    //            System.out.println(num + Thread.currentThread().getName());
            },"b").start();
    //
    //      
    //
        }
    
    //    private volatile static boolean isStop = false;
    //    public static void main(String[] args) {
    //        new Thread(()->{
    //            System.out.println("thread2 is start!");
    //
    //            while (!isStop) {
    //                
    //            }
    //            System.out.println("thread2 is going to stop!");
    //        }).start();
    //
    //        try {
    //            TimeUnit.SECONDS.sleep(2);
    //        } catch (InterruptedException e) {
    //            e.printStackTrace();
    //        }
    //
    //
    //        isStop = true;
    //        System.out.println("---->stop");
    //    }
    
    
        
        
    //    private static int MY_INT = 0;
    //    private static CountDownLatch signal = new CountDownLatch(1);
    //
    //    /**
    //     * 主线程启动2个测试子线程
    //     *
    //     * @param args null
    //     */
    //    public static void main(String[] args) {
    ////        new ChangeListener().start();
    ////        new ChangeMaker().start();
    //        Thread a = new ChangeListener();
    //        Thread b = new ChangeMaker();
    //        b.start();
    //        a.start();
    //        signal.countDown();
    //    }
    //
    //    /**
    //     * 此线程负责对MY_INT值改变的侦听,如果有改变就会打印出来
    //     */
    //    static class ChangeListener extends Thread {
    //        @Override
    //        public void run(){
    //            try{
    //                signal.await();
    //                int local_value = MY_INT;
    //                while (local_value < 50) {
    //                    if (local_value != MY_INT) { //关键代码
    //                        System.out.println("Got Change for MY_INT + MY_INT);
    //                        local_value = MY_INT;
    //                    }
    //                }
    //            }catch (Exception ex){                
    //            }
    //            
    ////            while (true) {
    ////                int local_value = MY_INT;
    ////                System.out.println(local_value);
    ////                if (local_value != MY_INT) { //关键代码
    ////                    System.out.println("Got Change for MY_INT : " + MY_INT);
    //////                    local_value = MY_INT;
    ////                }
    ////            }
    //        }
    //    }
    //
    //    /**
    //     * 此线程负责改变MY_INT的值
    //     */
    //    static class ChangeMaker extends Thread {
    //        @Override
    //        public void run() {
    //            try{
    //                signal.await();
    //                int local_value = MY_INT;
    //                while (MY_INT < 50) {
    //                    System.out.println("Incrementing MY_INT to " + (local_value + 1));
    //                    MY_INT = ++local_value;
    ////                MY_INT = 1+local_val
    //                    try {
    //                        Thread.sleep(100);
    //                    } catch (InterruptedException e) {
    //                        e.printStackTrace();
    //                    }
    //          
    //                }
    //            }catch (Exception e){
    //                
    //            }
    //        }
    //    }
        
    }
    

    2.不保证原子性

    原子性:不可分割

    线程A在执行任务的时候,不能被打扰的,也不能被分割.要么同时成功,要么同时执行.

    //不保证原子性
    public class VDemo02 {
        
        private volatile static int num = 0;
        
        static void add(){
            num ++;
        }
    
        public static void main(String[] args) {
            //理论是20000000
            for (int i = 0; i < 20; i++) {
                new Thread(()->{
                    for (int i1 = 0; i1 < 1000000; i1++) {
                        add();
                    }
                }).start();
            }
            
            while (Thread.activeCount() > 2){
                Thread.yield();
            }
            System.out.println(Thread.currentThread().getName() + "----------->" +num);
        }
    }
    

    不使用锁 使用原子类更高效,这些类的底层都直接和操作系统挂钩!在内存中修改值! Unsafe类是一个很特别的存在.

    
    import java.util.concurrent.atomic.AtomicInteger;
    
    //不保证原子性
    public class VDemo02 {
        
        private volatile static AtomicInteger num = new AtomicInteger();
        
        static void add(){
    //        num ++;
            num.getAndIncrement(); //cas
        }
        
    
        public static void main(String[] args) {
            //理论是20000000
            for (int i = 0; i < 20; i++) {
                new Thread(()->{
                    for (int i1 = 0; i1 < 1000000; i1++) {
                        add();
                    }
                }).start();
            }
            
            while (Thread.activeCount() > 2){
                Thread.yield();
            }
            System.out.println(Thread.currentThread().getName() + "----------->" +num);
        }
    }
    
    

    指令重排

    什么是 指令重排:你写的程序,计算机并不是按照你写的那样去执行的.

    源代码-->编译器优化代码(重排)-->指令并行也可能会重排-->内存系统也可能会重排-->执行

    处理器在进行指令重排的时候,考虑:数据之间的依赖性

    非计算机专业

    volatile 可以避免指令重排:

    内存屏障,cup指令,作用:

    1.保证特定的操作的执行顺序!

    2.可以保证某些变量的内存可见性(利用这些特性volatile实现了可见性)

    volatile 是可以保持可见性.不能保证院子性,由于内存屏障,可以保证避免指令重排的线程产生.

    18.彻底玩转单例模式

    饿汉式

    //饿汉式单例
    public class Hungry {
    
        private Hungry() {
        }
        
        private final static Hungry HUNGRY = new Hungry();
        
        public static Hungry getInstance(){
            return HUNGRY;
        }
    }
    
    

    懒汉式 dcl

    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    
    //懒汉式
    public class LazyMan {
    
        private LazyMan() {
            synchronized (LazyMan.class){
                if(lazyMan != null){
                    throw new RuntimeException("不要试图使用反射");
                }
            }
        }
        
        private volatile static LazyMan lazyMan;
        
        //双重检测  懒汉式单例  DCI懒汉式 (反射可以破坏)
        public static LazyMan getInstance(){
            if(lazyMan == null) {
                synchronized (LazyMan.class){
                    if (lazyMan == null) {
                        lazyMan = new LazyMan();//不是原子性操作
                    }
                }
            }
            return lazyMan;
        }
    
        //反射
        public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
            LazyMan instance = LazyMan.getInstance();
            Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
            declaredConstructor.setAccessible(true);
            LazyMan instance1 = declaredConstructor.newInstance();
            System.out.println(instance);
            System.out.println(instance1);
            
        }
        
        
        
    //    public static void main(String[] args) {
    //        for (int i = 10; i > 0; i--) {
    //            new Thread(()->{
    //                getInstance();
    //            }).start();
    //        }
    //        
    //    }
    }
    
    

    内部类

    /**
     * 静态内部类
     */
    public class Holer {
    
        private Holer(){
            
        }
        
        public static Holer getInstance(){
            return InnerClass.HOLER;     
        }
        
        public static class InnerClass{
            private static final Holer HOLER = new Holer();
        }
        
    }
    
    

    单例不安全使用

    枚举

    /**
     * enum 是一个什么? 本身也是一个class类
     * 
     * jad  反编译更为专业
     */
    public enum EnumSingle {
        
        INSTANCE;
        
        public EnumSingle getInstance(){
            return INSTANCE;
        }
        
        
    }
    

    枚举类型的最终的反编译源码:

    // Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
    // Jad home page: http://www.kpdus.com/jad.html
    // Decompiler options: packimports(3) 
    // Source File Name:   EnumSingle.java
    
    package com.mj.juc.single;
    
    import java.io.PrintStream;
    
    public final class EnumSingle extends Enum
    {
    
        public static EnumSingle[] values()
        {
            return (EnumSingle[])$VALUES.clone();
        }
    
        public static EnumSingle valueOf(String name)
        {
            return (EnumSingle)Enum.valueOf(com/mj/juc/single/EnumSingle, name);
        }
    
        private EnumSingle(String s, int i)
        {
            super(s, i);
        }
    
        public EnumSingle getInstance()
        {
            return INSTANCE;
        }
    
        public static void main(String args[])
        {
            EnumSingle instance = INSTANCE;
            System.out.println(instance);
        }
        public static final EnumSingle INSTANCE;
        private static final EnumSingle $VALUES[];
    
        static 
        {
            INSTANCE = new EnumSingle("INSTANCE", 0);
            $VALUES = (new EnumSingle[] {
                INSTANCE
            });
        }
    }
    
    

    19.深入理解CAS

    什么是cas

    import java.util.concurrent.atomic.AtomicInteger;
    
    public class CasDemo {
    
        public static void main(String[] args) {
            AtomicInteger atomicInteger = new AtomicInteger(2020);
    
            //如果达到了期望值  就更新 否则就不更新
            System.out.println(atomicInteger.compareAndSet(2020, 2021));
            System.out.println(atomicInteger.get());
            System.out.println(atomicInteger.compareAndSet(2020, 2021));
            System.out.println(atomicInteger.get());
        }
    }
    

    cas:比较当前工作内存中的值和主内存的值,如果这个值是期望的,那么则执行操作!如果不是就一直循环!! 自带原子性

    缺点:

    1. 循环会耗时;

    2. 一次性只能保证一个共享变量的原子性;

    20.原子引用

    解决ABA问题,引入原子引用! 对应的思想:乐观锁

    import java.util.concurrent.atomic.AtomicStampedReference;
    
    /**
     * 原子引用
     */
    public class AtomicTest {
        
        //AtomicStampedReference 注意 如果泛型是包装类,注意对象的引用问题
        static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(1,1);
    
        public static void main(String[] args) {
            
            
            new Thread(()->{
                int temp = atomicStampedReference.getStamp();//获取最新的版本号
    
                System.out.println(Thread.currentThread().getName() + "=========>"+ atomicStampedReference.getStamp());
    
                System.out.println(atomicStampedReference.compareAndSet(1, 2, atomicStampedReference.getStamp(), atomicStampedReference.getStamp()  + 1));
                
                System.out.println(Thread.currentThread().getName() + "=========>"+ atomicStampedReference.getStamp());
    
                System.out.println(atomicStampedReference.compareAndSet(2, 1, atomicStampedReference.getStamp(), atomicStampedReference.getStamp()+ 1));
                System.out.println(Thread.currentThread().getName() + "=========>"+ atomicStampedReference.getStamp());
                
            },"a").start();
    
    
            new Thread(()->{
                int temp = atomicStampedReference.getStamp();//获取最新的版本号
    
                System.out.println(Thread.currentThread().getName() + "=========>"+ atomicStampedReference.getStamp());
    
                System.out.println(atomicStampedReference.compareAndSet(1, 3, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1));
    
            },"b").start();
        }
    }
    

    21.各种锁的理解

    1.公平锁 非公平锁

    公平锁:非常公平 不能插队 先来的先执行!

    非公平锁:非常不公平 可以插队 (默认都是非公平锁)

    	public ReentrantLock() {
            sync = new NonfairSync();
        }
    
        public ReentrantLock(boolean fair) {
            sync = fair ? new FairSync() : new NonfairSync();
        }
    

    2.可重入锁(递归锁)

    synchronized

    public class Demo01 {
    
        public static void main(String[] args) {
            Phone phone = new Phone();
            
            new Thread(()->{
                phone.sms();
            },"A").start();
    
    
    
            new Thread(()->{
                phone.sms();
            },"B").start();
        }
    }
    
    class Phone{
        
        public synchronized void sms(){
            System.out.println(Thread.currentThread().getName() + "sms()");
            call();
        }
    
    
        public synchronized void call(){
            System.out.println(Thread.currentThread().getName() + "send()");
        }
    }
    
    

    lock版

    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class Demo02 {
    
        public static void main(String[] args) {
            Phone2 phone = new Phone2();
    
            new Thread(()->{
                phone.sms();
            },"A").start();
    
    
            new Thread(()->{
                phone.sms();
            },"B").start();
        }
    }
    
    class Phone2{
    
        Lock lock = new ReentrantLock();
        
        public void sms(){
            lock.lock();//细节问题 lock.unlock(); //lock 锁必须配对,否则就会死在里面
            try {
                System.out.println(Thread.currentThread().getName() + "sms()");
                call();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
        
    
    
        public void call(){
            lock.lock();
            try {
                System.out.println(Thread.currentThread().getName() + "send()");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }
    
    

    3.自旋锁

    自定义锁

    import java.util.concurrent.atomic.AtomicReference;
    
    /**
     * 自旋锁
     * @author Administrator
     */
    public class SpinlockDemo {
    
        AtomicReference<Thread> atomicReference = new AtomicReference<Thread>();
        
        //加锁
        void lock(){
            Thread thread = Thread.currentThread();
            System.out.println(Thread.currentThread().getName() + "==>lock");
            while (!atomicReference.compareAndSet(null,thread)){
                
            }
        }
    
    
        //加锁
        void unlock(){
            Thread thread = Thread.currentThread();
            System.out.println(Thread.currentThread().getName() + "==>unlock");
            atomicReference.compareAndSet(thread,null);
        }
    }
    
    

    测试

    import java.util.concurrent.TimeUnit;
    
    public class SpinlockTest {
    
        public static void main(String[] args) {
            SpinlockDemo lock = new SpinlockDemo();
            
            
            new Thread(()->{
                lock.lock();
                try {
                    TimeUnit.SECONDS.sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            },"a").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();
                }
            },"B").start();
        }
    }
    

    4.死锁

    测试类

    import java.util.concurrent.TimeUnit;
    public class DeadLockDemo {
    
    
        public static void main(String[] args) {
            
            String locka = "locka";       
            String lockb = "lockb";
            
            new Thread(new MyThread(locka,lockb),"a").start();
            new Thread(new MyThread(lockb,locka),"b").start();
        }
    }
    
    class MyThread implements Runnable{
    
        String lockA;
        String lockB;
    
        public MyThread(String lockA, String lockB) {
            this.lockA = lockA;
            this.lockB = lockB;
        }
    
        @Override
        public void run() {
            synchronized (lockA){
                System.out.println(Thread.currentThread().getName() + "lock" + lockB);
                try {
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lockB){
                    System.out.println(Thread.currentThread().getName() + "lock" + lockA);
                }
                
            }
        }
    }
    
    

    排查解决问题

    1.使用jps -l定位进程号;

    2.使用jstack 进程号 查看进程号信息;

  • 相关阅读:
    Unity Shader入门精要学习笔记
    Unity Shader入门精要学习笔记
    zabbix_server部署,启动,及端口未监听问题
    Linux Git服务器安装
    GitHub
    nginx 认证访问web
    Jenkins可持续集成
    svn
    mariadb安装配置
    nginx跟tp5无法加载控制器
  • 原文地址:https://www.cnblogs.com/HHbJ/p/14648249.html
Copyright © 2020-2023  润新知