高并发--02 JUC

  1. 什么是JUC?

​ java.util.current的简称。

​ 管程的概念:

​ 一种同步机制,保证同一时间只有一个线程访问被保护数据或者代码。

​ 用户线程:平时用到的多是用户线程

​ 守护线程:比如主线程Main

  1. 创建线程的四种方式:

    (1)继承Thread

    (2)实现Runnable

    (3)使用callable

    (4)使用线程池

  2. synchronize

    自动释放锁

  3. Lock接口

    目的:手动释放锁

    可重入锁:对某线程头标记,可重复加锁或者解锁。

    start()方法默认执行native方法,资源交给操作系统执行。

    与synchornize区别:

    (1)synchronized是Java中关键字,Lock是一个接口

    (2)Lock可以等待锁的线程响应中断,而synchronized不行

    (3)可知道是否成功获取锁,synchronized不行。

  4. 多线程编程步骤

  5. package org.example;
    
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    class Ticket4{
        private int number = 0;
        private Lock lock = new ReentrantLock();
        private Condition condition = lock.newCondition();
    
        public void add() {
            lock.lock();
            try {
                while (number != 0){
                    condition.await();
                }
                number++;
                System.out.println(Thread.currentThread().getName()+"::"+number);
                condition.signalAll();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }
    
        public void decr(){
            //加锁
            lock.lock();
            try {
                while (number != 1){
                    //睡眠,释放锁
                    condition.await();
                }
                number--;
                System.out.println(Thread.currentThread().getName()+"::"+number);
                //通知
                condition.signalAll();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                //释放锁
                lock.unlock();
            }
        }
    }
    public class LockImplInter {
        public static void main(String[] args) {
            Ticket4 ticket4 = new Ticket4();
            new Thread(()->{
                for (int i = 0; i < 10; i++) {
                    ticket4.add();
                }
            },"aa").start();
    
            new Thread(()->{
                for (int i = 0; i < 10; i++) {
                    ticket4.decr();
                }
            },"bb").start();
        }
    }
    
    
  6. 步骤:

​ (1)公共资源定义

​ (2)判断、干活、通知

​ (3)防止虚假唤醒,将判断条件放在while循环中,wait()特 性:在哪里睡在哪里唤醒,所以这里用await,可以循环判断。

  1. 定制化通信

    1. 启动三个线程,按照如下要求:

      AA打印5次,BB打印10次,CC打印15次

      进行10轮。

    2. 思路流程图

A
判断flag=1,打印5次,修改标志位flag=2,通知B
B
判断flag=2,打印10次,修改flag=3,通知C
C
if flag=3,print 15 times,change flag=1,notify A
package org.example;

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

class ShareResource{
    private int flag = 1;   // flag=1是A,flag=2是B,flag=3是c
    private Lock lock = new ReentrantLock();
    private Condition c1 = lock.newCondition();
    private Condition c2 = lock.newCondition();
    private Condition c3 = lock.newCondition();

    public void print5(int loop) throws InterruptedException {
        //上锁
        lock.lock();
        try {
            while (flag!=1){
                c1.await();
            }
            for (int i = 1; i < 6; i++) {
                System.out.println(Thread.currentThread().getName()+"::"+i+"::"+"轮数"+loop);
            }
            //修改标志位
            flag=2;
            //定向唤醒
            c2.signal();
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            //释放锁
            lock.unlock();
        }
    }

    public void pring11(int loop) throws InterruptedException{
        lock.lock();
        try {
            while (flag !=2){
                c2.await();
            }
            for (int i = 1; i < 11; i++) {
                System.out.println(Thread.currentThread().getName()+"::"+i+"::"+"轮数"+loop);
            }
            flag = 3;
            c3.signal();//唤醒c3
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void pring15(int loop) throws InterruptedException{
        lock.lock();
        try {
            while (flag!=3){
                c3.await();
            }
            for (int i = 1; i < 16; i++) {
                System.out.println(Thread.currentThread().getName()+":"+i+"论述:"+loop);
            }
            flag = 1;
            c1.signal();

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
public class DingXiangHuanxin {
    public static void main(String[] args) {
        ShareResource shareResource = new ShareResource();
        new Thread(()->{
            for (int i = 1; i < 11; i++) {
                try {
                    shareResource.print5(i);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"aa").start();

        new Thread(()->{
            for (int i = 1; i < 11; i++) {
                try {
                    shareResource.pring11(i);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"bb").start();

        new Thread(()->{
            for (int i = 1; i < 11; i++) {
                try {
                    shareResource.pring15(i);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"cc").start();
    }
}

  1. 几种list的创建方式

    package org.example;
    
    import java.util.*;
    import java.util.concurrent.CopyOnWriteArrayList;
    
    public class ListTest {
        public static void main(String[] args) {
            //(1)ArrayList不安全
            //(2)List<String> list = new ArrayList<>();
            //(3)List<String> list = new Vector<>();
            //(4)Collections.synchronizedList
    //        List<String> list = Collections.synchronizedList(new ArrayList<>());
            //(5)写时复制技术
            List<String> list = new CopyOnWriteArrayList<>();
            //循环创建线程
            for (int i = 0; i < 30; i++) {
                new Thread(()->{
                    list.add(UUID.randomUUID().toString().substring(0,8));
                    System.out.println(list);
                },String.valueOf(i)).start();
            }
        }
    }
    
    

    写时复制技术:写的时候先复制一块,写完后再读取新的集合,进行合并。

    部分源码:

    public CopyOnWriteArrayList(Collection<? extends E> c) {
            Object[] elements;
            if (c.getClass() == CopyOnWriteArrayList.class)
                elements = ((CopyOnWriteArrayList<?>)c).getArray();
            else {
                elements = c.toArray();
                if (c.getClass() != ArrayList.class)
                    elements = Arrays.copyOf(elements, elements.length, Object[].class);
            }
            setArray(elements);
        }
    

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w39WHfxA-1670402441087)(image-20221206102932793.png)]

  1. concurrentHashMap()

    package org.example;
    
    import java.util.*;
    import java.util.concurrent.ConcurrentHashMap;
    
    public class MapTest {
            public static void main(String[] args) {
                //不安全
    //            Map<String,String> map = new HashMap<>();
                //解决
                Map<String,String> map = new ConcurrentHashMap<>();
                //循环创建线程
                for (int i = 0; i < 30; i++) {
                    String key = String.valueOf(i);
                    new Thread(()->{
                        map.put(key,UUID.randomUUID().toString().substring(0,8));
                        System.out.println(map);
                    },String.valueOf(i)).start();
                }
            }
    }
    
    
  2. 公平锁与非公平锁

    1. 公平锁:效率低
    2. 非公平锁:效率高,但是会出现线程饿死的情况,比如synchronized就是非公平锁,而ReentrantLock默认非公平锁,可设置入参为true为公平锁。
  3. 可重入锁 (递归锁)

    1. synchronized(隐式),lock(显示)

    2. 线程中对同一个对象加了多次同一把锁

      package org.example;
      class DiguiLock{
      	public synchronized void add(){
      		add();//容易出现栈溢出问题
      	}
      }
      public class ReInLock {
          public static void main(String[] args) {
              Object o = new Object();
              new Thread(()->{
                  synchronized (o){
                      System.out.println(Thread.currentThread().getName()+"外层");
                      synchronized (o){
                          System.out.println(Thread.currentThread().getName()+"中层");
                          synchronized (o){
                              System.out.println(Thread.currentThread().getName()+"内层");
                          }
                      }
                  }
              },"aa").start();
          }
      }
      
      
    3. lock接口演示可重入锁

      package org.example;
      
      import java.util.concurrent.locks.Lock;
      import java.util.concurrent.locks.ReentrantLock;
      
      public class Lockyanshi {
          public static void main(String[] args) {
              Lock lock = new ReentrantLock();
              new Thread(()->{
                  try {
                      lock.lock();
                      System.out.println("aaa");
                      try {
                          lock.lock();
                          System.out.println("bbb");
      
                      } catch (Exception e) {
                          e.printStackTrace();
                      } finally {
                          lock.unlock();
                      }
                  } catch (Exception e) {
                      e.printStackTrace();
                  } finally {
                      lock.unlock();
                  }
              },"t1").start();
      
              new Thread(()->{
                  lock.lock();
                  System.out.println("ccc");
                  lock.unlock();
              },"cc").start();
          }
      }
      
      

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d0rQWOwl-1670402441089)(image-20221206111235695.png)]

  1. 死锁

    1. 什么是死锁:

      两个或两个以上进程执行过程中,因争夺资源造成互相等待现象,无外力干涉则无法继续执行。

      1. 验证是否死锁:

      (1)jps -l

      (2)jstack 端口号

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SiRr2vxH-1670402441090)(image-20221206111616984.png)]

  2. callable

    1. 接口,相对于runnable,有返回值,如果没有则抛异常

    2. 实现方法名称不同,callable是call方法,而runnable是run()方法。

    3. 实现方式

      找一个类,既和Runnable有关系,又和Callable有关系

      Runnable接口有实现类FutureTask,可传递callable接口

      类似适配器模式

    4. FutureTask的使用

      package org.example;
      
      import java.util.concurrent.Callable;
      import java.util.concurrent.FutureTask;
      
      class MyThread1 implements Runnable{
      
          @Override
          public void run() {
      
          }
      }
      class Mythread2 implements Callable{
      
          @Override
          public Integer call() throws Exception {
              return 200;
          }
      }
      public class CallAndRunTest {
          public static void main(String[] args) {
              new Thread(new MyThread1(),"aa").start();
      //        报错
      //        new Thread(new Mythread2(),"bb").start();
              /**
               * futuretask  未来任务
               * 例子:老师上课(主线程),口渴买水。
               * 1.不影响主线程,需要某些值时,单开线程,get即可
               * 2.多个子线程之间对同一个资源的汇总,
               * 3.某个步骤迟迟得不到结果,先挂起,先做完其他任务。
               */
              FutureTask<Integer> task = new FutureTask<>(new Mythread2());
              //函数式接口可用lambda表达式
              FutureTask<Integer> task2 = new FutureTask<>(()->{
                  return 20;
              });
              
          }
      }
      
      
  3. 辅助类

    (1)countdown演示,减少计数

    package org.example;
    
    import java.util.concurrent.CountDownLatch;
    
    public class CountDownTest {
        public static void main(String[] args) throws InterruptedException {
            //设置初始值是6
            CountDownLatch countDownLatch = new CountDownLatch(6);
            for (int i = 0; i < 6; i++) {
                new Thread(()->{
                    System.out.println(Thread.currentThread().getName()+" 号同学离开了教室");
                    //计数-1
                    countDownLatch.countDown();
                },String.valueOf(i)).start();
            }
    
                countDownLatch.await();
            //主线程
            System.out.println(Thread.currentThread().getName()+"班长关门");
        }
    }
    
    

    (2)CyclicBarrier(循环栅栏)

    例子:集齐七颗龙珠召唤神龙

    package org.example;
    
    import java.util.concurrent.BrokenBarrierException;
    import java.util.concurrent.CyclicBarrier;
    
    public class CyclicBarrierDemo {
        private static final int NUMBER = 7;
        public static void main(String[] args) {
    
            CyclicBarrier cyclicBarrier = new CyclicBarrier(NUMBER,new Thread(()->{
                System.out.println("集齐7颗龙珠才能召唤神龙");
            }));
    
            for (int i = 0; i < 7; i++) {
                new Thread(()->{
                    System.out.println(Thread.currentThread().getName()+" 星龙珠被收集到了");
                    try {
                        cyclicBarrier.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                },String.valueOf(i)).start();
            }
        }
    }
    
    

(3)Semaphore:信号量,6辆汽车,3个停车位,相当于三把锁

package org.example;

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

public class Semophere {

    public static void main(String[] args) {
        //创建Semaphore,3个许可量,相当于三把锁
        //场景:秒杀场景
        Semaphore semaphore = new Semaphore(3);
        for (int i = 0; i < 6; i++) {
            new Thread(()->{
                //抢占线程
                try {
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName()+"抢到了车位");
                    TimeUnit.SECONDS.sleep(new Random().nextInt(5));
                    System.out.println(Thread.currentThread().getName()+"离开了车位");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    semaphore.release();
                }
            },String.valueOf(i)).start();
        }

    }
}

  1. 悲观锁与乐观锁

    1. 悲观:每次读写都加锁,不支持并发操作

    2. 乐观:版本控制,对同一资源 操作时,通过版本号控制,谁先提交就用谁的。

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i2FsX7Pf-1670402441091)(image-20221207101238830.png)]

  2. 表锁与行锁,都会发生死锁,写等读或者读等写

    1. 表锁:对象为一个表,锁整个表

    2. 行锁:一行记录

      表锁与行锁都会发生死锁。

      行锁
      读锁,也叫共享锁
      写锁,也叫独占锁

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PoUXIjM3-1670402441091)(image-20221207102337530.png)]

  1. 虚假唤醒

    (1)循环操作中使用了wait方法时,由于wait方法在哪里睡在哪里醒的特性,会出现虚假唤醒的情况。

    (2)判断条件不足

    (3)金融方面会出现-1的可能。

  2. 读写锁案例

    package org.example;
    
    import java.util.HashMap;
    import java.util.Map;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.locks.ReadWriteLock;
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    class Myache{
        //volatile,并发保证资源可见性,以及不可重排序,非原子性
        private volatile Map<String,Object> map = new HashMap<>();
        private ReadWriteLock rwLock = new ReentrantReadWriteLock();
        //放数据
        public void put(String key,Object value){
            rwLock.writeLock().lock();
            try {
                System.out.println(Thread.currentThread().getName()+"...正在写操作"+key);
                TimeUnit.MICROSECONDS.sleep(300);
                map.put(key,value);
                System.out.println(Thread.currentThread().getName()+"写完了"+key);
    
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                rwLock.writeLock().unlock();
            }
        }
    
        //取数据
        public Object getValue(String key){
            rwLock.readLock().lock();
            Object result = null;
            System.out.println(Thread.currentThread().getName()+"正在获取:"+key);
            try {
                TimeUnit.MICROSECONDS.sleep(300);
                result = map.get(key);
                System.out.println(Thread.currentThread().getName()+"已经取完了"+key);
    
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                rwLock.readLock().unlock();
            }
            return result;
        }
    }
    public class ReadWriteLockTest {
    
        public static void main(String[] args) {
            Myache myache = new Myache();
            for (int i = 0; i < 6; i++) {
                final int number = i;
                new Thread(()->{
                    myache.put(number+"",number+"");
                },String.valueOf(i)).start();
            }
    
            for (int i = 0; i < 6; i++) {
                final int number = i;
                new Thread(()->{
                    myache.getValue(number+"");
                },String.valueOf(i)).start();
            }
        }
    }
    
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wsQFrin3-1670402441092)(image-20221207132450039.png)]

  3. 读写锁:一个资源可以被多个读线程访问,或者可以被一个写线程访问,但是不能同时存在读写线程,读写互斥,读读共享。

  4. 锁降级:写锁降为读锁的过程。

    写锁只有一个线程,自然不能把别的线程赶走降级为读锁;因此,就只能是写锁降级为读锁了。先写后读。

    package org.example;
    
    import java.util.HashMap;
    import java.util.Map;
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    //锁降级过程     加写锁(可重入)--》加读锁-->释放写锁--》释放读锁
    public class WriteToReadLock {
        public static void main(String[] args) {
            ReentrantReadWriteLock reentrantLock = new ReentrantReadWriteLock();
            ReentrantReadWriteLock.ReadLock readLock = reentrantLock.readLock();
            ReentrantReadWriteLock.WriteLock writeLock = reentrantLock.writeLock();
    
            Map<String,String> map = new HashMap<>();
            writeLock.lock();
            System.out.println("写锁线程执行");
            map.put("123","看你吗");
            //说明写锁进行时,读锁可以进入该线程进行读操作
            readLock.lock();
            System.out.println("获取读锁");
            String readValue = map.get("123");
            System.out.println(Thread.currentThread().getName()+"号线程读到了值:"+readValue);
            //释放写锁
            writeLock.unlock();
            //释放读锁
            readLock.unlock();
        }
    }
    
    

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TnRUWJ2o-1670402441092)(image-20221207134157290.png)]

  1. 队列与栈

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qmvYqMjF-1670402441093)(image-20221207134629847.png)]

  2. 阻塞队列

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P7ZhqcWz-1670402441093)(image-20221207135100033.png)]

    1. 当队列是空时读线程阻塞,在队列不为空的时候自动唤醒

    2. 当队列是空时写线程唤醒,在队列满时写线程阻塞

      唤醒与阻塞由队列一手包办,无需考虑在什么时候执行唤醒或者阻塞操作。

    3. 分类:

      (1)有界队列:ArrayBlockingQueue,维护一个固定长度的链表。

      (2)链表队列:LinkedBlcokingQueue,等等。

    4. 阻塞队列核心方法:

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Nmq35qfh-1670402441093)(image-20221207140153079.png)]

    5. 阻塞队列操作演示:

      package org.example;
      
      import java.util.concurrent.ArrayBlockingQueue;
      import java.util.concurrent.BlockingQueue;
      import java.util.concurrent.TimeUnit;
      
      public class BlockingQueueTest {
          public static void main(String[] args) throws InterruptedException {
              //创建阻塞队列
              BlockingQueue blockingQueue = new ArrayBlockingQueue(3);
              //元素操作方法:
              //第一种方法
              //添加元素
              System.out.println(blockingQueue.add("a"));
              System.out.println(blockingQueue.add("b"));
              System.out.println(blockingQueue.add("c"));
              //检查元素
              System.out.println(blockingQueue.element());
      
              //删除元素
              System.out.println(blockingQueue.remove());
              System.out.println(blockingQueue.remove());
              System.out.println(blockingQueue.remove());
              //删多会报异常
      //        System.out.println(blockingQueue.remove());
      
              BlockingQueue blockingQueue1 = new ArrayBlockingQueue(3);
              //第二种方法
              //添加值
              blockingQueue1.offer("a");
              blockingQueue1.offer("b");
              blockingQueue1.offer("c");
              //取值
              System.out.println(blockingQueue1.poll());
              System.out.println(blockingQueue1.poll());
              System.out.println(blockingQueue1.poll());
              //为空时会输出空值,但是不会报异常
              System.out.println(blockingQueue1.poll());
      
              //put、get特点:队列满时写入会一直阻塞,可以加个判断条件
              BlockingQueue blockingQueue2 = new ArrayBlockingQueue(3);
              blockingQueue2.offer("a");
              blockingQueue2.offer("b");
              blockingQueue2.offer("c");
              System.out.println(blockingQueue2.offer("d", 3L, TimeUnit.SECONDS));
      
              System.out.println(blockingQueue2.take());
              System.out.println(blockingQueue2.take());
              System.out.println(blockingQueue2.take());
              System.out.println(blockingQueue2.take());
          }
      }
      
      
  3. 线程池

    1. 概念:

      维护多个线程,等待监督管理者分配可执行任务。

      优点:

      (1)降低资源消耗

      (2)提高响应速度

      (3)提高线程的可管理型

      (4)Java中的线程池是通过Executor框架实现的,该框架中用到的Executor,Exceutors,ExecutorService,ThreadPoolExecutor这几个类,涉及到双亲委派机制。

    2. 分类:

      (1)一池多线程:Executors.newFixedThreadPool(int)

      (2)一池一线程:Executors.newSingleThreadPool()

      (3)可扩容线程:Executors.newCachedThreadPool()

    3. 线程池使用演示:

      package org.example;
      
      import java.util.concurrent.ExecutorService;
      import java.util.concurrent.Executors;
      
      public class ThreadPoolTest {
          public static void main(String[] args) {
              //一对多,定长
      //        ExecutorService threadPool = Executors.newFixedThreadPool(5);
      //        一池一线程
      //        ExecutorService threadPool = Executors.newSingleThreadExecutor();
      //        可扩展线程
              ExecutorService threadPool = Executors.newCachedThreadPool();
              try {
                  for (int i = 0; i < 10; i++) {
                      threadPool.execute(()->{
                          System.out.println(Thread.currentThread().getName()+"办理业务");
                      });
                  }
              } catch (Exception e) {
                  e.printStackTrace();
              } finally {
                  //给线程池打上一个不可用标记
                  threadPool.shutdown();
              }
          }
      }
      
      
  4. ThreadPool七个参数

    1. int corePoolSize 常驻线程池数量(核心)
    2. int maximumPoolSize 最大核心线程数
    3. long keepAliveTime 非核心线程数空闲时存活时间
    4. TimeUnit unit
    5. BlockingQueue workQueue 阻塞队列
    6. ThreadFactory threadFactory 线程工厂
    7. RejectedExecutionHandler handler 拒绝策略
  5. 线程池工作流程和拒绝策略

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MWCQIRNX-1670402441094)(image-20221207150819770.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WG2XWxQJ-1670402441094)(image-20221207151219264.png)]

AbortPolicy(默认):直接抛出RejectedExecutionException异常阻止系统正常运行

CallerRunsPolicy:调用者运行,一种调节机制,该策略图不会抛弃任务,不会抛出异常,而是将某些任务回退到调用者,从而降低新任务的流量。

DiscardOldestPolicy:抛弃队列中等待时间最长的任务

DiscardPolicy:无法处理任务,不予任何处理也不跑异常。

  1. 自定义线程池

    package org.example;
    
    import java.util.concurrent.ArrayBlockingQueue;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;
    
    public class CustomThreadPool {
        public static void main(String[] args) {
            ThreadPoolExecutor customPool = new ThreadPoolExecutor(
                    2,
                    5,
                    3L,
                    TimeUnit.SECONDS,
                    new ArrayBlockingQueue<>(3),
                    Executors.defaultThreadFactory(),
                    new ThreadPoolExecutor.AbortPolicy()
            );
    
            try {
                for (int i = 0; i < 10; i++) {
                    //只有在execute这一步才是创建线程池完成
                    customPool.execute(()->{
                        System.out.println(Thread.currentThread().getName()+"自定义线程池");
                    });
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                //关闭线程池(不可用标记)
                customPool.shutdown();
            }
        }
    }
    
    
  2. 异步回调

    1. 同步:某线程请求做某事,锁未释放,阻塞,等待锁释放后执行以后操作。
    2. 异步:比如找同学办点事,同学不在,继续忙别的,请求别人同学回来了告诉我。
    3. A定义回调函数,注册到B的响应函数,事件触发,B调用响应函数,响应函数调用回调函数。

演示:

package org.example;

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

public class CompleableFutureTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //同步回调,无返回值
        CompletableFuture<Void> voidcompletableFuture = CompletableFuture.runAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "同步回调");
        });
        voidcompletableFuture.get();

        //异步回调,有返回值
        CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "异步回调");
            //模拟异常
            int i = 1/0;
            return 1024;
        });

        Integer integerValue = completableFuture.get();
        System.out.println(integerValue);
    }
}

关于回调,写了个简单的回调测试demo

package org.example.huidiao;

public class A {
    int number = 1;
    public int callbackFunction(){

        System.out.println("A定义了回调函数");
        return number;
    }
}

package org.example.huidiao;

public class B {
    public void responseFunction(){
        Integer bNumber = 1;
        //注册A的回调函数
        A a = new A();

        int number = a.number;
        //响应条件:bNumber的值等于A中的全局变量number
        if (bNumber.equals(number)){
            System.out.println("条件满足,B的响应函数调用A的回调函数");
            int callNumber = a.callbackFunction();
            System.out.println(callNumber);
        }else {
            System.out.println("条件不满足,只输出B的响应函数");
        }
    }

    public static void main(String[] args) {
        B b = new B();
        b.responseFunction();
    }
}

nt i = 1/0;
return 1024;
});

    Integer integerValue = completableFuture.get();
    System.out.println(integerValue);
}

}


关于回调,写了个简单的回调测试demo

package org.example.huidiao;

public class A {
int number = 1;
public int callbackFunction(){

    System.out.println("A定义了回调函数");
    return number;
}

}


package org.example.huidiao;

public class B {
public void responseFunction(){
Integer bNumber = 1;
//注册A的回调函数
A a = new A();

    int number = a.number;
    //响应条件:bNumber的值等于A中的全局变量number
    if (bNumber.equals(number)){
        System.out.println("条件满足,B的响应函数调用A的回调函数");
        int callNumber = a.callbackFunction();
        System.out.println(callNumber);
    }else {
        System.out.println("条件不满足,只输出B的响应函数");
    }
}

public static void main(String[] args) {
    B b = new B();
    b.responseFunction();
}

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

超级无敌暴龙战士塔塔开

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值