多线程进阶=》JUC并发编程02

在JUC并发编程01中说到了,什么是JUC、线程和进程、Lock锁、生产者和消费者问题、8锁现象、集合类不安全、Callable(简单)、常用辅助类、读写锁
https://blog.csdn.net/qq_45441466/article/details/117197861

10、阻塞队列

在这里插入图片描述
阻塞队列:BlockingDeque
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
什么情况下我们会使用阻塞队列:
多线程并发处理,线程池!

学会使用队列
添加、移除

四组API

方式抛出异常由返回值阻塞等待超时等待
添加addoffer()put()offer(“d”, 2,TimeUnit.SECONDS)
移除removepoll()take()poll(2,TimeUnit.SECONDS)
判断队列首elementpeek()
package com.panghl.juc.bq;


import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;

/**
 * @Author panghl
 * @Date 2021/6/1 19:28
 * @Description BlockQueue
 **/
public class Test {
    public static void main(String[] args) throws InterruptedException {
//        test1();
//        test2();
//        test3();
        test4();
    }

    /**
     * 抛出异常
     */
    public static void test1(){
        //队列的大小
        ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
        System.out.println(blockingQueue.add("A"));
        System.out.println(blockingQueue.add("B"));
        System.out.println(blockingQueue.add("C"));
        //IllegalStateException: Queue full 抛出异常!
        //System.out.println(blockingQueue.add("d"));


        System.out.println(blockingQueue.remove());
        System.out.println(blockingQueue.remove());
        System.out.println(blockingQueue.remove());
        //java.util.NoSuchElementException 抛出异常
//        System.out.println(blockingQueue.remove());
        System.out.println(blockingQueue.peek());//检测队首元素
        System.out.println(blockingQueue.element());//查看队首元素是谁

    }

    /**
     * 有返回值
     */
    public static void test2(){
        BlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
        System.out.println(blockingQueue.offer("A"));
        System.out.println(blockingQueue.offer("B"));
        System.out.println(blockingQueue.offer("C"));
        System.out.println(blockingQueue.offer("d")); //false 不抛出异常!

        System.out.println(blockingQueue.element());//查看队首元素是谁

        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());

        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.peek());//检测队首元素
        System.out.println(blockingQueue.element());//查看队首元素是谁
    }

    /**
     * 等待,阻塞(一直阻塞)
     */
    public static void test3() throws InterruptedException {
        BlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
        //一直阻塞
        blockingQueue.put("a");
        blockingQueue.put("b");
        blockingQueue.put("c");
        blockingQueue.put("d"); //队列没有位置了,一直阻塞
        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take());

        System.out.println(blockingQueue.take()); //没有这个元素,一直阻塞
    }

    /**
     * 超时等待
     */
    public static void test4() throws InterruptedException {
        BlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
        //一直阻塞
        blockingQueue.offer("a");
        blockingQueue.offer("b");
        blockingQueue.offer("c");
//        blockingQueue.offer("d", 2,TimeUnit.SECONDS); //2s 后无位置,超时退出

        blockingQueue.poll();
        blockingQueue.poll();
        blockingQueue.poll();
        blockingQueue.poll(2,TimeUnit.SECONDS);//等待超过2s就退出
   }
}

同步队列

没有容量,进去一个元素,必须等待取出来之后,才能往里面放一个元素!
put、take

package com.panghl.juc.bq;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;

/**
 * @Author panghl
 * @Date 2021/6/1 20:21
 * @Description 同步队列
 * 和其他的BlockingQueue 不一样,SynchronousQueue 不存储元素
 * put了一个元素,必须从里面先take取出来,否则不能再put进去值!
 **/
public class SyncQueueDemo {
    public static void main(String[] args) {
        //同步队列
        BlockingQueue<String> syncQueue = new SynchronousQueue<>();
        new Thread(() -> {
            try {
                System.out.println(Thread.currentThread().getName() + "put 1");
                syncQueue.put("1");
                System.out.println(Thread.currentThread().getName() + "put 2");
                syncQueue.put("2");
                System.out.println(Thread.currentThread().getName() + "put 3");
                syncQueue.put("3");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "T1").start();

        new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
                System.out.println(Thread.currentThread().getName() + "take 1");
                syncQueue.take();
                TimeUnit.SECONDS.sleep(2);
                System.out.println(Thread.currentThread().getName() + "take 2");
                syncQueue.take();
                TimeUnit.SECONDS.sleep(2);
                System.out.println(Thread.currentThread().getName() + "take 3");
                syncQueue.take();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "T2").start();
    }
}

11、线程池(重点)

池化技术:程序的运行,本质:占用系统的资源!优化资源的使用!事先准备好一些资源,有人要用,就来我这里拿,用完之后还给我。

线程池的好处
1、降低资源的消耗
2、提高响应的速度
3、方便管理

线程复用,可以控制最大并发数、管理线程

线程池:三大方法

在这里插入图片描述

package com.panghl.juc.pool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @Author panghl
 * @Date 2021/6/1 20:37
 * @Description 工具类 :3大方法
 * 使用了线程池之后,使用线程池来创建线程
 **/
public class Demo01 {
    public static void main(String[] args) {
//        ExecutorService threadPool = Executors.newSingleThreadExecutor();//单个线程
//        ExecutorService threadPool = Executors.newFixedThreadPool(5); //创建一个固定的线程池的大小
        ExecutorService threadPool = Executors.newCachedThreadPool(); //可伸缩的,遇强则强,遇弱则弱

        try {
            for (int i = 0; i < 10; i++) {
                threadPool.execute(() -> {
                    System.out.println(Thread.currentThread().getName() + "ok");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //线程池用完,程序结束,关闭线程池
            threadPool.shutdown();
        }
    }
}

7大参数

    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }
       
public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
 }
 
public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      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.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

在这里插入图片描述

手动创建一个线程池

四种拒绝策略

package com.panghl.juc.pool;

import java.util.concurrent.*;

/**
 * @Author panghl
 * @Date 2021/6/1 20:37
 * @Description 工具类 :4种拒绝策略
new ThreadPoolExecutor.AbortPolicy() //银行满了,还有人进来,不处理这个人的,抛出异常
new ThreadPoolExecutor.CallerRunsPolicy() //哪来的去哪里! main线程执行
new ThreadPoolExecutor.DiscardPolicy() //队列满了,丢掉任务,不会抛出异常!
new ThreadPoolExecutor.DiscardOldestPolicy() //队列满了,尝试去和最早的竞争,也不会抛出异常!

 **/
public class Demo02 {
    public static void main(String[] args) {
       // 自定义线程池!工作 ThreadPoolExecutor
       ExecutorService threadPool = new ThreadPoolExecutor(
               2,
               5,
               3,
               TimeUnit.SECONDS,
               new LinkedBlockingQueue<>(3),
               Executors.defaultThreadFactory(),
               new ThreadPoolExecutor.DiscardOldestPolicy() //队列满了,尝试去和最早的竞争,也不会抛出异常!
       );

        try {
            //最大承载:Deque + max
            //超过 RejectedExecutionException
            for (int i = 1; i <=9; i++) {
                threadPool.execute(() -> {
                    System.out.println(Thread.currentThread().getName() + "ok");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //线程池用完,程序结束,关闭线程池
            threadPool.shutdown();
        }
    }
}

在这里插入图片描述

new ThreadPoolExecutor.AbortPolicy() //银行满了,还有人进来,不处理这个人的,抛出异常 new
ThreadPoolExecutor.CallerRunsPolicy() //哪来的去哪里! main线程执行 new
ThreadPoolExecutor.DiscardPolicy() //队列满了,丢掉任务,不会抛出异常! new
ThreadPoolExecutor.DiscardOldestPolicy() //队列满了,尝试去和最早的竞争,也不会抛出异常!

小结和扩展
最大线程到底该如何定义?
1、CPU 密集型 ; 几核,就是几,可以保持CPU的效率最高!
2、IO 密集型 ; 判断你程序中十分耗IO的线程。
程序 15个大型任务 io十分占用资源!

package com.panghl.juc.pool;

import java.util.concurrent.*;

/**
 * @Author panghl
 * @Date 2021/6/1 20:37
 * @Description 工具类 :4种拒绝策略
new ThreadPoolExecutor.AbortPolicy() //银行满了,还有人进来,不处理这个人的,抛出异常
new ThreadPoolExecutor.CallerRunsPolicy() //哪来的去哪里! main线程执行
new ThreadPoolExecutor.DiscardPolicy() //队列满了,丢掉任务,不会抛出异常!
new ThreadPoolExecutor.DiscardOldestPolicy() //队列满了,尝试去和最早的竞争,也不会抛出异常!

 **/
public class Demo02 {
    public static void main(String[] args) {
       // 自定义线程池!工作 ThreadPoolExecutor

        //最大线程到底该如何定义?
        //1、CPU  密集型 ; 几核,就是几,可以保持CPU的效率最高!
        //2、IO   密集型 ; 判断你程序中十分耗IO的线程。
            //      程序  15个大型任务  io十分占用资源!

        //获取CPU的核数
        System.out.println(Runtime.getRuntime().availableProcessors());
        ExecutorService threadPool = new ThreadPoolExecutor(
               2,
                Runtime.getRuntime().availableProcessors(),
               3,
               TimeUnit.SECONDS,
               new LinkedBlockingQueue<>(3),
               Executors.defaultThreadFactory(),
               new ThreadPoolExecutor.DiscardOldestPolicy() //队列满了,尝试去和最早的竞争,也不会抛出异常!
       );

        try {
            //最大承载:Deque + max
            //超过 RejectedExecutionException
            for (int i = 1; i <=9; i++) {
                threadPool.execute(() -> {
                    System.out.println(Thread.currentThread().getName() + "ok");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //线程池用完,程序结束,关闭线程池
            threadPool.shutdown();
        }
    }
}

12、四大函数式接口(必须掌握)

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}
//超级多FunctionalInterface
//简化编程模型,在新版本的框架底层大量应用!
//foreach (消费者类的函数式接口)

在这里插入图片描述
代码测试:

Function函数式接口

package com.panghl.juc.function;

import java.util.function.Function;

/**
 * @Author panghl
 * @Date 2021/6/1 21:32
 * @Description Function 函数式接口,有一个输入参数,有一个输出
 * 只要是函数式接口可以用lambda表达式简化
 **/
public class Demo01 {
    public static void main(String[] args) {
        //工具类:输出输入的值
//        Function<String, String> function = new Function<String, String>() {
//            @Override
//            public String apply(String o) {
//                return o;
//            }
//        };
        Function<String, String> function = (str)->{return str;};
        System.out.println(function.apply("1"));
    }
}

断定型接口

在这里插入图片描述

package com.panghl.juc.function;

import java.util.function.Predicate;

/**
 * @Author panghl
 * @Date 2021/6/1 21:40
 * @Description 断定性接口:有一个输入参数,返回值只能是 布尔值!
 **/
public class Demo2 {
    public static void main(String[] args) {
        //判断字符串是否为null
//        Predicate<String> predicate = new Predicate<String>() {
//            @Override
//            public boolean test(String o) {
//                return o.isEmpty();
//            }
//        };
        Predicate<String> predicate = (str)->{return str.isEmpty();};
        System.out.println(predicate.test("1"));
    }
}

Consumer 消费型接口
在这里插入图片描述

package com.panghl.juc.function;

import java.util.function.Consumer;

/**
 * @Author panghl
 * @Date 2021/6/1 21:48
 * @Description Consumer 消费型接口:只有输入,没有返回值
 **/
public class Demo03 {
    public static void main(String[] args) {
//        Consumer<String> consumer = new Consumer<String>() {
//            @Override
//            public void accept(String str) {
//                System.out.println(str);
//            }
//        };

        Consumer<String> consumer = (str) -> {
            System.out.println(str);
        };
        consumer.accept("helo");
    }
}

Supplier 供给型接口

在这里插入图片描述

package com.panghl.juc.function;

import java.util.function.Supplier;

/**
 * @Author panghl
 * @Date 2021/6/1 21:50
 * @Description Supplier 供给型接口,没有参数,只有返回值
 **/
public class Demo04 {
    public static void main(String[] args) {
//        Supplier<String> supplier = new Supplier<String>() {
//            @Override
//            public String get() {
//                return "helo";
//            }
//        };

        Supplier<String> supplier = ()->{return "adhelo";};
        System.out.println(supplier.get());
    }
}

13、Stream流式计算

在这里插入图片描述

package com.panghl.juc.stream;

import java.util.Arrays;
import java.util.List;

/**
 * @Author panghl
 * @Date 2021/6/1 21:58
 * @Description 题目要求:一分钟内完成此题,只能用一行代码实现!
 * 1、ID必须是偶数
 * 2、年龄必须大于23岁
 * 3、用户名转为大写字母
 * 4、用户名字母倒着排序
 * 5、只输出一个用户!
 **/
public class Test {
    public static void main(String[] args) {
        User u1 = new User(1, "a", 21);
        User u2 = new User(2, "b", 22);
        User u3 = new User(3, "c", 23);
        User u4 = new User(4, "d", 24);
        User u5 = new User(5, "e", 25);

        List<User> users = Arrays.asList(u1, u2, u3, u4, u5);
        users.stream()
                .filter((u) -> {
                    return u.getId() % 2 == 0;
                })
                .filter((u)->{
                 return u.getAge()>23;
                })
                .map((u)->{return u.getName().toUpperCase();})
                .sorted((o1,o2)->{return o1.compareTo(o2);})
                .limit(1)
                .forEach(System.out::println);
    }
}

14、ForkJoin

什么是ForkJoin
ForkJoin在JDK1.7,并执行任务!提高效率。大数据量!
大数据:Map Reduce(把大任务拆分为小任务)
在这里插入图片描述
ForkJoin特点:工作窃取
这个里面维护的都是双端队列
在这里插入图片描述
ForkJoin

在这里插入图片描述

package com.panghl.juc.forkjoin;

import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;

/**
 * @Author panghl
 * @Date 2021/6/2 22:30
 * @Description 求和计算的任务!
 * 3000 6000(ForkJoin) 9000(Stream并行流)
 * 如何使用forkjoin ?
 * 1、forkjoinPool 通过它来执行
 * 2、计算任务 forkjoinPool.execute(ForkJoinTask task)
 * 3、要继承ForkJoinTask
 **/
public class ForkJoinDemo extends RecursiveTask<Long> {
    private Long start; //1
    private Long end;  //1990900000

    //临界值
    private Long temp = 10000L;


    public ForkJoinDemo(Long start, Long end) {
        this.start = start;
        this.end = end;
    }

    @Override
    protected Long compute() {
        if ((end - start) > temp) {
            //分支合并计算
            Long sum = 0L;
            for (Long i = start; i < end; i++) {
                sum += i;
            }
            System.out.println(sum);
            return sum;
        } else { //forkjoin
            long middle = (start + end) / 2; //中间值
            ForkJoinDemo forkJoinDemo1 = new ForkJoinDemo(start, middle);
            forkJoinDemo1.fork(); //拆分任务,把任务压入线程队列
            ForkJoinDemo forkJoinDemo2 = new ForkJoinDemo(middle + 1, end);
            forkJoinDemo2.fork();
            return forkJoinDemo1.join() + forkJoinDemo2.join();
        }

    }


}

package com.panghl.juc.forkjoin;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.stream.LongStream;

/**
 * @Author panghl
 * @Date 2021/6/2 22:45
 * @Description TODO
 **/
public class Test {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        test3();
    }

    public static void test1(){
        Long sum = 0L;
        long start = System.currentTimeMillis();
        for (Long i = 1L; i < 10_0000_000; i++) {
            sum+=i;
        }
        long end = System.currentTimeMillis();
        System.out.println("sum="+"时间:"+(end-start));
    }
    //会使用ForkJoin
    public static void test2() throws ExecutionException, InterruptedException {
        long start = System.currentTimeMillis();
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        ForkJoinDemo forkJoinDemo = new ForkJoinDemo(0L,10_0000_000L);
        ForkJoinTask<Long> forkJoinTask = forkJoinPool.submit(forkJoinDemo);
        Long aLong = forkJoinTask.get();
        long end = System.currentTimeMillis();
        System.out.println("sum="+aLong+"时间:"+(end-start));
    }
    //Stream并行流
    public static void test3(){
        long start = System.currentTimeMillis();
        long reduce = LongStream.rangeClosed(0L, 10_0000_000L).parallel().reduce(0, Long::sum);

        long end = System.currentTimeMillis();
        System.out.println("sum="+reduce+"时间:"+(end-start));
    }
}

15、异步回调

package com.panghl.juc.future;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * @Author panghl
 * @Date 2021/6/2 23:02
 * @Description 异步调用: Ajax
 * 异步执行  成功回调
 **/
public class Demo01 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //发送一个请求--》没有返回值的runAsync 异步回调
//        CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(()->{
//            try {
//                TimeUnit.SECONDS.sleep(2);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//            System.out.println(Thread.currentThread().getName()+"休眠结束===>runSync=>Void");
//        });
//        System.out.println("1111");
//        completableFuture.get(); //获取阻塞执行结果

        //有返回值的 supplyAsync 异步回调
        //ajax,成功和失败的回调
        //返回的是错误信息;
        CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(()->{
            int i = 1/0;
            System.out.println(Thread.currentThread().getName()+"休眠结束===>runSync=>Integer");
            return 1024;
        });

        completableFuture.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());
            return 233; //可以获取到错误的返回结果
        });
        Integer integer = completableFuture.get();
        System.out.println(integer);

    }
}

16、JMM

Volatile是Java虚拟机提供轻量级的同步机制
1、保证可见性
2、不保证原子性
3、禁止指令重排

什么是JMM?
JMM:Java内存模型,不存在的东西,概念!约定!

关于JMM的一些同步的约定:
1、线程解锁前,必须把共享变量立刻刷回主存。
2、线程加锁前,必须读取主存中的最新值到工作内存中!
3、加锁和解锁是同一把锁

线程 工作内存主内存
8中操作:

在这里插入图片描述
在这里插入图片描述

问题:程序不知道主内存的值被修改了。

package com.panghl.juc.volatil;

import java.util.concurrent.TimeUnit;

/**
 * @Author panghl
 * @Date 2021/6/2 23:36
 * @Description
 **/
public class JMMDemo {
    private static  int num = 0;

    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {//线程1
            while (num == 0) {

            }
        }).start();

        TimeUnit.SECONDS.sleep(2);

        num = 1;
        System.out.println(num);
    }

}

在这里插入图片描述

18.Volatile

1、保证了可见性

package com.panghl.juc.volatil;

import java.util.concurrent.TimeUnit;

/**
 * @Author panghl
 * @Date 2021/6/2 23:36
 * @Description
 **/
public class JMMDemo {
    private static volatile int num = 0;

    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {//线程1
            while (num == 0) {

            }
        }).start();

        TimeUnit.SECONDS.sleep(2);

        num = 1;
        System.out.println(num);
    }

}

2、不保证原子性
原子性:不可分割
线程A在执行任务的时候,不能被打扰,也不能被分割。要么同时成功,要嘛同时失败。

package com.panghl.juc.volatil;

/**
 * @Author panghl
 * @Date 2021/6/2 23:44
 * @Description 不保证原子性
 **/
public class VDemo02 {
    private volatile static int num = 0;

    private static void add(){
        num++;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 20; i++) {
            new Thread(()->{
                for (int i1 = 0; i1 < 1000; i1++) {
                    add();
                }
            }).start();
        }

        while (Thread.activeCount()>2){//main gc 默认执行
                Thread.yield();
        }

        System.out.println(Thread.currentThread().getName()+"==>num:"+num);
    }
}

在这里插入图片描述
如果不加lock和synchronized,怎么样保证原子性?
在这里插入图片描述
使用原子类,解决原子性问题

package com.panghl.juc.volatil;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Author panghl
 * @Date 2021/6/2 23:44
 * @Description 不保证原子性
 **/
public class VDemo02 {
    //原子类的 Integer
    private volatile static AtomicInteger num = new AtomicInteger();

    private static void add(){
//        num++; //你是一个原子性操作
        num.getAndIncrement(); //AtomicInteger+1 的方法, CAS
    }

    public static void main(String[] args) {
        for (int i = 0; i < 20; i++) {
            new Thread(()->{
                for (int i1 = 0; i1 < 1000; i1++) {
                    add();
                }
            }).start();
        }

        while (Thread.activeCount()>2){//main gc 默认执行
                Thread.yield();
        }

        System.out.println(Thread.currentThread().getName()+"==>num:"+num);
    }
}

这些类的底层都直接和操作系统挂钩!在内存中修改值!Unsafe类是一个很特殊的存在!

3、指令重排
什么是指令重排:你写的程序,计算机并不是按照你写的那样去执行的。
源代码–》编译器优化的重排–》指令并行也可能会重排–》内存系统也会重排–》执行

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

int x =1; //1
int y = 2; //2
x=x+5; //3
y=x*x; //4
我们所期望的:1234 结果2134 1324

可能造成影响的结果: ab xy 这四个值默认都是0;

线程A线程B
x=ay=b
b=1a=2

正常的结果:x=0;y=0 ;但是可能由于指令重排

线程A线程B
b=1a=2
x=ay=b

指令重排导致的诡异结果:x=2;y=1;

volatile 可以避免指令重排
内存屏障。CPU指令。作用:
1、保证特定的操作的执行顺序!
2、可以保证某些变量的内存可见性(利用这些特性volatile实现了可见性)

volatile是可以保证可见性。不能保证原子性,由于内存屏障,可以保证避免指令重排的现象产生!

20、深入理解CAS

什么是CAS
大厂必须要深入研究底层!有所突破!修内功,操作系统,计算机网络原理

Unsafe类

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
CAS: 比较当前工作内存中的值和主内存的值,如果这个值是期望的,那么执行操作!如果不是就一直循环。

缺点:
1、循环会耗时
2、一次性只能保证一个共享变量的原子性
3、ABA问题

CAS:ABA问题(狸猫换太子)
在这里插入图片描述

package com.panghl.juc.cas;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Author panghl
 * @Date 2021/6/3 21:33
 * @Description TODO
 **/
public class CASDemo {
    //CAS compareAndSet: 比较并交换!
    public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(2020);
        
        // 期望、更新
        // public final boolean compareAndSet(int expect, int update)
        //如果我期望的值达到了,name就更新,否则,就不更新,CAS 是CPU的并发原语
        atomicInteger.compareAndSet(2020,2021);
        System.out.println(atomicInteger.get());
        // ===============捣乱的线程============
        System.out.println(atomicInteger.compareAndSet(2020,2021));
        System.out.println(atomicInteger.get());
        System.out.println(atomicInteger.compareAndSet(2021,2020));
        System.out.println(atomicInteger.get());

        // ===============期望的线程============
        System.out.println(atomicInteger.compareAndSet(2020,6666));
        System.out.println(atomicInteger.get());


    }
}

21、原子引用

解决ABA问题,引入原子引用!对应的思想:乐观锁
带版本号的原子操作。
注意
在这里插入图片描述

package com.panghl.juc.cas;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * @Author panghl
 * @Date 2021/6/3 21:33
 * @Description TODO
 **/
public class CASDemo {
    //CAS compareAndSet: 比较并交换!
    public static void main(String[] args) {
//        AtomicInteger atomicInteger = new AtomicInteger(2020);
        //int Integer 注意,如果泛型是一个包装类,注意对象的引用问题!!!
        //正常在业务操作,这里面比较的都是一个个对象
        AtomicStampedReference<Integer> atomicReference = new AtomicStampedReference<>(1,1);
        // 乐观锁的原理相同!!!
        new Thread(()->{
            int stamp = atomicReference.getStamp(); //获取版本号
            System.out.println("A1->"+stamp);
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(atomicReference.compareAndSet(1, 2, atomicReference.getStamp(), atomicReference.getStamp() + 1));

            System.out.println("A2->"+atomicReference.getStamp());
            System.out.println(atomicReference.compareAndSet(2, 1, atomicReference.getStamp(), atomicReference.getStamp() + 1));

            System.out.println("A2->"+atomicReference.getStamp());
        },"A").start();

        new Thread(()->{
            int stamp = atomicReference.getStamp(); //获取版本号
            System.out.println("B1->"+stamp);

            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(atomicReference.compareAndSet(1, 3, stamp, stamp + 1));
            System.out.println("B2->"+atomicReference.getStamp());
        },"B").start();
    }
}


21、各种锁的理解

1、公平锁、非公平锁
公平锁:非常公平,不能够插队,必须先来后到!
非公平锁:非常不公平,可以插队(默认非公平锁)
在这里插入图片描述

2、可重入锁
可重入锁(递归锁)
在这里插入图片描述

Synchronized版本

package com.panghl.juc.lock;

/**
 * @Author panghl
 * @Date 2021/6/3 22:16
 * @Description 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("打电话");
    }
}

Lock版本

package com.panghl.juc.lock;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Author panghl
 * @Date 2021/6/3 22:19
 * @Description Lock
 **/
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 锁必须配对,否则就会死在里面
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + "sms");
            call(); //这里也有锁
        } catch (Exception e) {
            e.getMessage();
        } finally {
            lock.unlock();
            lock.unlock();
        }

    }

    public void call() {
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName() +"打电话");
        } catch (Exception e) {
            e.getMessage();
        } finally {
            lock.unlock();
        }
    }
}


3、自旋锁
在这里插入图片描述
自定义锁测试:

package com.panghl.juc.lock;

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

/**
 * @Author panghl
 * @Date 2021/6/3 22:26
 * @Description 自旋锁
 **/
public class SpinlockDemo {
    // int 0
    // Thread null
    AtomicReference<Thread> atomicReference = new AtomicReference<>();

    //加锁
    public void myLock(){
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName()+"==>lock");

        // 自旋锁
        while (!atomicReference.compareAndSet(null,thread)){
            System.out.println("自旋中....");
        }
    }


    //解锁
    public void myUnLock(){
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName()+"==>myUnlock");
        atomicReference.compareAndSet(thread,null);
    }

}

package com.panghl.juc.lock;

import java.util.concurrent.TimeUnit;

/**
 * @Author panghl
 * @Date 2021/6/3 22:30
 * @Description
 **/
public class TestSpinLock {
    public static void main(String[] args) {
        //底层使用的自旋锁CAS
        SpinlockDemo spinlockDemo = new SpinlockDemo();
        new Thread(()->{
            spinlockDemo.myLock();

            try {
                TimeUnit.SECONDS.sleep(3);
            }catch (Exception e){
                e.getMessage();
            }finally {
                spinlockDemo.myUnLock();
            }
        },"A1").start();
        new Thread(()->{
            spinlockDemo.myLock();

            try {
                TimeUnit.SECONDS.sleep(1);
            }catch (Exception e){
                e.getMessage();
            }finally {
                spinlockDemo.myUnLock();
            }
        },"A2").start();
    }
}

4、死锁
在这里插入图片描述
死锁测试,怎么排除死锁:

package com.panghl.juc.lock;

import java.util.concurrent.TimeUnit;

/**
 * @Author panghl
 * @Date 2021/6/3 22:37
 * @Description 死锁
 **/
public class DeadLockDemo {
    public static void main(String[] args) {
        String lockA="lockA";
        String lockB="lockB";

        new Thread(new MyThread(lockA,lockB),"A1").start();
        new Thread(new MyThread(lockB,lockA),"A2").start();

    }
}

class MyThread implements Runnable{
    private String lockA;
    private 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:"+lockA+"=>get"+lockB);

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

            synchronized (lockB){
                System.out.println(Thread.currentThread().getName()+"lock:"+lockB+"=>get"+lockA);
            }
        }
    }
}

解决问题
1、使用 jps -l 定位进程号
在这里插入图片描述
2、使用 jstack 进程号 找到死锁问题
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
基于微信小程序的家政服务预约系统采用PHP语言和微信小程序技术,数据库采用Mysql,运行软件为微信开发者工具。本系统实现了管理员和客户、员工三个角色的功能。管理员的功能为客户管理、员工管理、家政服务管理、服务预约管理、员工风采管理、客户需求管理、接单管理等。客户的功能为查看家政服务进行预约和发布自己的需求以及管理预约信息和接单信息等。员工可以查看预约信息和进行接单。本系统实现了网上预约家政服务的流程化管理,可以帮助工作人员的管理工作和帮助客户查询家政服务的相关信息,改变了客户找家政服务的方式,提高了预约家政服务的效率。 本系统是针对网上预约家政服务开发的工作管理系统,包括到所有的工作内容。可以使网上预约家政服务的工作合理化和流程化。本系统包括手机端设计和电脑端设计,有界面和数据库。本系统的使用角色分为管理员和客户、员工三个身份。管理员可以管理系统里的所有信息。员工可以发布服务信息和查询客户的需求进行接单。客户可以发布需求和预约家政服务以及管理预约信息、接单信息。 本功能可以实现家政服务信息的查询和删除,管理员添加家政服务信息功能填写正确的信息就可以实现家政服务信息的添加,点击家政服务信息管理功能可以看到基于微信小程序的家政服务预约系统里所有家政服务的信息,在添加家政服务信息的界面里需要填写标题信息,当信息填写不正确就会造成家政服务信息添加失败。员工风采信息可以使客户更好的了解员工。员工风采信息管理的流程为,管理员点击员工风采信息管理功能,查看员工风采信息,点击员工风采信息添加功能,输入员工风采信息然后点击提交按钮就可以完成员工风采信息的添加。客户需求信息关系着客户的家政服务预约,管理员可以查询和修改客户需求信息,还可以查看客户需求的添加时间。接单信息属于本系统里的核心数据,管理员可以对接单的信息进行查询。本功能设计的目的可以使家政服务进行及时的安排。管理员可以查询员工信息,可以进行修改删除。 客户可以查看自己的预约和修改自己的资料并发布需求以及管理接单信息等。 在首页里可以看到管理员添加和管理的信息,客户可以在首页里进行家政服务的预约和公司介绍信息的了解。 员工可以查询客户需求进行接单以及管理家政服务信息和留言信息、收藏信息等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值