JUC

1、what?

JUC就是java.util.concurrent下面的类包,专门用于多线程的开发。

2、why?

解决多线程、高并发

3、how?
   ||

   ||

  ﹀

point1:volatile关键字与内存可见性;

question1:多个线程共享资源时,彼此不可见; ​ 可以给资源加锁,但是加锁,线程会阻塞,效率较低;如何在不使用锁的情况下,更新资源,即给资源加上volatile关键字。

point2:原子性

原子变量:Java提供了原子变量,在java.util.concurrent.atomic包下; ​ 使用CAS(Compare And Swap)来保证原子性;当内存值==预估值时,我才会把更新值更新到内存。但此时会出现一个ABA问题,即一个线程修改变量A,为B再改回A,此时CAS察觉不到,被修改了,当然基本数据类型是不要紧的,但如果是引用数据呢?这个对象中有多个变量,我不知道有没有被修改。因此,增加版本号就成了一个很好的选择;

point3:锁分段机制

在java.util.concurrent包中提供了多种并发容器类来改进同步容器类的性能。其中最主要的就是ConcurrentHashMap。 ​ ConcurrentHashMap采用了分段锁机制,是一个线程安全的hash表,我们知道HashMap不是线程安全的,HashTable加了锁,是线程安全的,因此他效率低。而ConcurrentHashMap默认分成了16个segment,每个segment对应一个hash表,且有自己独立的锁。所以每一个线程访问一个segment,就可以并行访问了,这大大的提高了效率;

point4:锁

1、传统锁synchronized关键字:

a、锁代码块、锁类; ​ b、当这个关键字锁到一个带有static的方法时,锁的是这个类模板。 ​

  1. class X{
  2. public Synchronized void f(){
  3. methods body...
  4. }
  5. }

2、Lock接口:

是在juc包下的,首先要声明一个可重入锁; ​ 有三个实现类:ReentrantLock(可重入锁 常用)、 ReentrantReadWriteLock.ReadLock(读锁)、ReentrantReadWriteLock.WriteLock(写锁)

  1. class X{
  2. Lock lock = new ReentrantLock();
  3. public void f(){
  4. lock.lock;
  5. try{
  6. method body.....
  7. }finally{
  8. lock.unlock;
  9. }
  10. }
  11. }

  

  1、公平锁:十分公平,先来后到; ​

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

3.lock与Synchronized的区别

  1. >1Synchronized是内置关键字;Lock是接口;
    >2Synchronized无法判断获取锁的状态;Lock可以判断;
    >3Synchronized会自动释放锁;Lock需要手动释放,不释放会出现死锁现象;
    >4Synchronized(当a线程获取锁并阻塞,b线程会一直等);Lock不会这样(tryLock()方法,当目前可以获取锁时返回true,反之false
    >5Synchronized是可重入锁、不可中断、非公平锁;Lock可重入、可判断锁、公平性(可以自定义),扩展性更好;
    >6Synchronized可以锁少量同步代码;Lock可以锁大量的同步代码;

4、锁的类型

可重入锁:拿到外面的锁后,会自动拿到里面的锁;

自旋锁

point5:生产者和消费者问题

1、线程之间通信问题:生产者和消费者问题! ​

2、三部曲:判断是否需要等待 this.wait() 、业务、通知 this.notifyAll() ​

3、线程的虚假唤醒问题,将if()改为while()判断;

  1. Condition condition = lock.newCondition();
    condition.await();//等待
    condition.signal();//通知

Condition实现精确通知

  1. Condition condition1 = lock1.newCondition();
    Condition condition2 = lock2.newCondition();
    Condition condition3 = lock3.newCondition();
    例子:当前condition1,要通知condition3,则要condition3.signal();

point6:8锁现象

1、多个线程使用同一个对象,多个线程就是使用一把锁,先调用的先执行!

2、多个线程使用同一个对象,多个线程就是使用一把锁,先调用的先执行,即使在某方法中设置了阻塞。

3、多个线程,有的线程有锁,有的线程没锁,两者之间不存在竞争同一把锁的情况,先后执行顺序是随机的。

4、a被 synchronized 修饰的方法,锁的对象是方法的调用者;b调用者不同,它们之间用的不是同一个锁,相互之间没有关系。

5、被 synchronized 和 static 同时修饰的方法,锁的对象是类的 class 对象,是唯一的一把锁。线程之间是顺序执行。

  锁Class和锁对象的区别:

    a、Class 锁 ,类模版,只有一个;

    b、对象锁 , 通过类模板可以new 多个对象。

6、被 synchronized 修饰 和 static 修饰的方法,锁的对象是类的 class 对象,是唯一的一把锁。

  Class锁是唯一的,所以多个对象使用的也是同一个Class锁。

  如果全部都锁了Class,那么这个类下的所有对象都具有同一把锁。

7、被 synchronized和static修饰的方法,锁的对象是类的class对象!唯一的同一把锁;

  只被synchronized修饰的方法,是普通锁(如对象锁),不是Class锁,所以进程之间执行顺序互不干扰。

解释见:https://blog.csdn.net/makyan/article/details/104524725

point7:集合不安全

异常:ConcurrentModificationException,并发修改异常;

解决方案: ​

  List<String> list =new ArrayList<String>();

  1、List<String> list = new Vector(); --->被synchronized修饰的方法效率很低; ​

  2、List<String> list = Collections.syncronizedList(new ArrayList<>()); ​

  3、List<String> list = new CopyOnWriteArrayList<>();

  Set<String> set = new HashSet<>();

​   1、Set<String> set = Collections.synchroniazedSet(new HashSet<>()); ​

  2、Set<String> set = new CopyOnWriteArraySet<>(); ​ HashSet本质就是用了HashMap的key不重复来实现去重的; ​

​   Map<String,String> map = new HashMap<>();

  1、Map<String,String> map = Collections.synchronizedMap<>(); ​

  2、Map<String,String>map = new ConcurrentHashMap<>();--->详情见point3

point8:Callable与Runable

先看一下两个接口的定义:

Callable

  1. public interface Callable<V> {
  2.   V call() throws Exception;
  3. }

Runnable

  1. interface Runnable {
  2.   public abstract void run();
  3. }

和明显能看到区别:

1.Callable能接受一个泛型,然后在call方法中返回一个这个类型的值。而Runnable的run方法没有返回值
2.Callable的call方法可以抛出异常,而Runnable的run方法不会抛出异常。

point9:常用辅助类

1、CountDownLatch 减法计数器

  1. CountDownLatch count=new CountDownLatch(5);
  2. for (int i = 1; i <=5 ; i++) {
  3. new Thread(()->{
  4. System.out.println(Thread.currentThread().getName()+"go out");
  5. count.countDown();//count--
  6. },String.valueOf(i)).start();
  7. }
  8. count.await();//等待计数器归零,然后向下执行
  9. System.out.println("over");

2、CyclicBarrier 加法计数器(集齐七龙珠召唤神龙)

  1. CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()-> System.out.println("召唤神龙"));
  2. for (int i = 1; i <=7 ; i++) {
  3. final int temp = i;
  4. new Thread(()->{
  5. System.out.println(Thread.currentThread().getName()+"收集第"+temp+"个龙珠");
  6. try {
  7. cyclicBarrier.await();//等待
  8. } catch (InterruptedException e) {
  9. e.printStackTrace();
  10. } catch (BrokenBarrierException e) {
  11. e.printStackTrace();
  12. }
  13. },String.valueOf(i)).start();
  14. }

3、Semaphore 流量

停车位,限流;三个车位,六辆车;

  1. //有3个停车位,有六辆车
  2. Semaphore semaphore = new Semaphore(3);
  3. for (int i = 1; i <=6 ; i++) {
  4. new Thread(()->{
  5. try {
  6. semaphore.acquire();//获取许可
  7. System.out.println(Thread.currentThread().getName()+"抢到车位");
  8. TimeUnit.SECONDS.sleep(2);
  9. System.out.println(Thread.currentThread().getName()+"离开车位");
  10. } catch (InterruptedException e) {
  11. e.printStackTrace();
  12. }finally{
  13. semaphore.release();//释放信号
  14. }
  15. },String.valueOf(i)).start();
  16. }

point10:读写锁

ReentrantReadWriteLock 看一下jdk源码:

point11:阻塞队列BlockingQueue

1、使用情况:
2、四种API:
方法 抛出异常 有返回值,不抛异常 阻塞等待 超时等待
添加 add() offer() put offer(Object o,Long timeout,TimeUnit t)
移除 remove() poll() take poll(Long timeout,TimeUnit t)
检测队首 element() peek    
  1. /**
  2. * 抛出异常
  3. */
  4. public static void test1(){
  5. ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue(3);
  6. System.out.println(arrayBlockingQueue.add("a"));
  7. System.out.println(arrayBlockingQueue.add("b"));
  8. System.out.println(arrayBlockingQueue.add("c"));
  9. //检查队首元素
  10. System.out.println(arrayBlockingQueue.element());
  11. System.out.println("=================");
  12. System.out.println(arrayBlockingQueue.remove());
  13. System.out.println(arrayBlockingQueue.remove());
  14. System.out.println(arrayBlockingQueue.remove());
  15. }
  1. /**
  2. * 有返回值,不抛出异常
  3. */
  4. public static void test2(){
  5. ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue(3);
  6. System.out.println(blockingQueue.offer("a"));
  7. System.out.println(blockingQueue.offer("b"));
  8. System.out.println(blockingQueue.offer("c"));
  9. System.out.println(blockingQueue.offer("c"));
  10. //查看队首元素
  11. System.out.println(blockingQueue.peek());
  12. System.out.println("=======================");
  13. System.out.println(blockingQueue.poll());
  14. System.out.println(blockingQueue.poll());
  15. System.out.println(blockingQueue.poll());
  16. System.out.println(blockingQueue.poll());
  17.  
  18. }
  1. /**
  2. * 阻塞等待
  3. */
  4. public static void test3(){
  5. ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue(3);
  6. try {
  7. blockingQueue.put("a");
  8. blockingQueue.put("b");
  9. blockingQueue.put("c");
  10. System.out.println("===");
  11. blockingQueue.take();
  12. blockingQueue.take();
  13. blockingQueue.take();
  14. } catch (InterruptedException e) {
  15. e.printStackTrace();
  16. }
  17.  
  18. }
  1. /**
  2. * 超时等待
  3. */
  4. public static void test4(){
  5. ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue(3);
  6. try {
  7. System.out.println(blockingQueue.offer("a", 2, TimeUnit.SECONDS));
  8. System.out.println(blockingQueue.offer("a", 2, TimeUnit.SECONDS));
  9. System.out.println(blockingQueue.offer("a", 2, TimeUnit.SECONDS));
  10. System.out.println(blockingQueue.offer("a", 2, TimeUnit.SECONDS));
  11. System.out.println("====================");
  12. System.out.println(blockingQueue.poll(2, TimeUnit.SECONDS));
  13. System.out.println(blockingQueue.poll(2, TimeUnit.SECONDS));
  14. System.out.println(blockingQueue.poll(2, TimeUnit.SECONDS));
  15. } catch (InterruptedException e) {
  16. e.printStackTrace();
  17. }
  18.  
  19. }

point12:SynchronousQueue同步队列

  同步队列和阻塞队列不同,同步队列不存储元素; 往里面put一个元素,必须要先take取出来;

point13:线程池(重点)

1、为什么要用线程池?线程池的好处?

  1. >a、降低资源的消耗,不用频繁的创先销毁线程;
  2. >b、提高响应速度
  3. >c、方便管理

2、三大方法、七大参数、四种拒绝策略

  A、三大方法
  1. //不要使用Executors工具类来创建线程池,用最原生的ThreadPoolExecutor;
  2. ExecutorService threadPool= Executors.newSingleThreadExecutor();//单个线程
  3. ExecutorService threadPool1=Executors.newFixedThreadPool(5);//固定线程
  4. ExecutorService threadPool2= Executors.newCachedThreadPool();//可变线程,遇强则强,遇弱则弱;
  5. try{
  6. for(int i=0;i<10;i++){
  7. //使用线程池创建线程
  8. threadPool.execute(()->{
  9. System.out.println(Thread.currentThread().getName()+"OK");
  10. })
  11. }
  12. }finally{
  13. threadPool.shoutdown();//线程池用完,程序关闭,最后关闭线程池
  14. }
  B、七大参数

  ThreadPoolExecutor

  1. public ThreadPoolExecutor(int corePoolSize,//核心线程数
  2. int maximumPoolSize,//允许最大线程数
  3. long keepAliveTime,//当线程数大于核心线程数时,这就是多余空闲线程的存活时间
  4. TimeUnit unit,//时间单位
  5. BlockingQueue<Runnable> workQueue,//在执行任务之前用于保留任务的队列。 此队列将仅保存execute方法提交的Runnable任务
  6. ThreadFactory threadFactory,//执行过程中创建新的线程所需要的工厂
  7. RejectedExecutionHandler handler//拒绝策略,当线程满了、阻塞队列也满了时会执行的策略
  8. )
  C、4种拒绝策略RejectedExecutionHandler:
  1. new ThreadPoolExecutor.AbortPolicy();//银行满了,还有人进来,不处理,抛异常;
  2. new ThreadPoolExecutor.CallerRunsPolicy();//哪里来的回哪里
  3. new ThreadPoolExecutor.DiscardOldestPolicy();//队列满了尝试和最早的竞争,不会抛出异常;
  4. new ThreadPoolExecutor.DiscardPolicy();//队列满了丢掉任务,不会抛异常;

3、最大线程怎么定义(调优)

A、CPU密集型 ​ 获取当前CPU的核数:Runtime.getRuntime().availableProcessors() ​ 最大线程==当前CPU核数

B、IO密集型 ​ 判断程序中十分耗IO的线程 ​ 最大线程 > 十分耗IO的线程数

point14:四大函数式接口(简化编程模型

函数型接口

  1. Function function = (str)->{ return str;};//有参数、有返回值

断定型接口

  1. Predicate<String> predicate =(str)->{return str.isEmpty();};//有参数,返回布尔值

消费性接口

  1. Consumer<String> consumer =(str)->{ System.out.println("已消费"); };//有参数,无返回值

供给型接口

  1. Supplier supplier=()->{return "你好";};//无参数,有返回值

ponit15:Stream流

  1. /* 筛选条件
  2. * 1、id为偶数
  3. * 2、年龄大于22
  4. * 3、名字转为大写
  5. * 4、倒序
  6. * 5、输出一个
  7. */
  8. User u1 =new User(1,"a",20);
  9. User u2 =new User(2,"b",21);
  10. User u3 =new User(3,"c",22);
  11. User u4 =new User(4,"d",23);
  12. User u5 =new User(5,"e",24);
  13. User u6 =new User(6,"f",25);
  14. List<User> list = Arrays.asList(u1, u2, u3, u4,u5,u6);
  15. list.stream().filter(u->{return u.getId()%2==0;})
  16. .filter(u->{return u.getAge()>22;})
  17. .map(u->{return u.getName().toUpperCase();})
  18. .sorted((uu1,uu2)->{return uu2.compareTo(uu1);})
  19. .limit(1)
  20. .forEach(System.out::println);

point16:ForkJoin

把一个大任务拆成多个小任务并行执行 ​ 例如:计算1-10亿内的数累加 ​ 使用ForkJoin可以提升速度,使用Stream流会更快

point17:异步回调

ComletableFuture

JUC学习!的更多相关文章

  1. JUC学习笔记(六)

    JUC学习笔记(一)https://www.cnblogs.com/lm66/p/15118407.html JUC学习笔记(二)https://www.cnblogs.com/lm66/p/1511 ...

  2. JUC学习笔记(五)

    JUC学习笔记(一)https://www.cnblogs.com/lm66/p/15118407.html JUC学习笔记(二)https://www.cnblogs.com/lm66/p/1511 ...

  3. JUC学习笔记(四)

    JUC学习笔记(一)https://www.cnblogs.com/lm66/p/15118407.html JUC学习笔记(二)https://www.cnblogs.com/lm66/p/1511 ...

  4. JUC学习笔记(三)

    JUC学习笔记(一)https://www.cnblogs.com/lm66/p/15118407.html JUC学习笔记(二)https://www.cnblogs.com/lm66/p/1511 ...

  5. JUC学习笔记(二)

    JUC学习笔记(一)https://www.cnblogs.com/lm66/p/15118407.html 1.Lock接口 1.1.Synchronized 1.1.1.Synchronized关 ...

  6. JUC学习笔记——进程与线程

    JUC学习笔记--进程与线程 在本系列内容中我们会对JUC做一个系统的学习,本片将会介绍JUC的进程与线程部分 我们会分为以下几部分进行介绍: 进程与线程 并发与并行 同步与异步 线程详解 进程与线程 ...

  7. JUC学习笔记——共享模型之管程

    JUC学习笔记--共享模型之管程 在本系列内容中我们会对JUC做一个系统的学习,本片将会介绍JUC的管程部分 我们会分为以下几部分进行介绍: 共享问题 共享问题解决方案 线程安全分析 Monitor ...

  8. JUC学习笔记——共享模型之内存

    JUC学习笔记--共享模型之内存 在本系列内容中我们会对JUC做一个系统的学习,本片将会介绍JUC的内存部分 我们会分为以下几部分进行介绍: Java内存模型 可见性 模式之两阶段终止 模式之Balk ...

  9. JUC学习记录

    先附上学习的博客地址:http://blog.csdn.net/cx8122389/article/details/70049425, 具体见该博客 Java JUC 简介 在Java 5.0 提供了 ...

  10. JUC学习笔记--Atomic原子类

    J.U.C 框架学习顺序 http://blog.csdn.net/chen7253886/article/details/52769111 Atomic 原子操作类包 Atomic包 主要是在多线程 ...

随机推荐

  1. python 迁移虚拟环境

    1.在源环境中获取包列表(新建文件夹whls) #cd 虚拟环境目录下的\scripts,cmd acitivate # 下载清单到requirements.txt,切换到whls目录 pip fre ...

  2. 用深度学习模型Word2Vec探索《红楼梦》人物关系

    先来看一看结果,发现: 1.贾宝玉和袭人的关系最近. 2.薛宝钗和自己的妈妈关系最近. 3.贾宝玉和林黛玉逼格比较统一,薛宝钗属于独树一帜的逼格调性. 4.大观园中可以看到邢岫烟经常出没... 还有更 ...

  3. Redis如何找出并快速删除亿级指定前缀的key

    背景 由于Redis的单线程服务模式,命令keys *会阻塞正常的业务请求,不建议使用keys * pattern的方法进行查询,可能会使服务器卡顿而出现事故.如何获取指定的 key? 可以采用Red ...

  4. mysql增删改查json中的某个字段

    创建表 1 CREATE TABLE t_json(id INT PRIMARY KEY, NAME VARCHAR(20), info JSON); 插入记录 1 INSERT INTO t_jso ...

  5. Java使用HSSFWorkbook生成Excel

    HSSF 是Horrible SpreadSheet Format的缩写,也即"讨厌的电子表格格式". 也许HSSF的名字有点滑稽,就本质而言它是一个非常严肃.正规的API.通过H ...

  6. 单文件WSDL,非模块化

    最近在使用CXF做WebService Sever端,接口与实现类不在一个包下. 实现类如下: 1 @WebService(serviceName = "Demo" 2 , tar ...

  7. JS篇(007)-事件委托是什么

    答案:利用事件冒泡的原理,让自己的所触发的事件,让他的父元素代替执行! 解析: 1.那什么样的事件可以用事件委托,什么样的事件不可以用呢? 适合用事件委托的事件:click,mousedown,mou ...

  8. JS篇(003)-请用 js 去除字符串空格?

    答案:replace 正则匹配方法.str.trim()方法.JQ 方法:$.trim(str)方法 解析: 方法一:replace 正则匹配方法 去除字符串内所有的空格:str = str.repl ...

  9. rpm制作(简)

    yum -y install gcc prec-devel openssl-devel zlib-devel yum -y install rpm-build #生成工作目录 rpmdev-setup ...

  10. grpc start with python

    pip install grpcio grpcio-tools syntax = "proto3"; service FutureData { rpc GetTick(ReqTic ...