4.多线程之JUC并发编程1

news2024/11/22 23:06:32

1.List集合类不安全(以前单线程永远是安全的,多线程集合就不安全了)

都是ConcurrentModificationException并发修改异常,在有sout输出的情况下出来的,因为多线程边读边写
//并发情况下ArrayList是不安全的 可以用Vector在jdk1.0出来的,List1.2出来的加了同步锁

  1. List list=new Vector<>(); //使用数组长度++还有一种就是判断数组长度,采用复制相同数组
  2. List list =Collections.synchronizedList(new ArrayList<>());//把他变安全
  3. 写入时复制,比Vector重锁效率高,使用可重入锁,读写分离避免覆盖 COW(Copy-on-write)是计算机程序设计领域的一直以来的优化策略(读写分离)
    List list =new CopyWroteArrayList(); //先复制给一个数组长度+1,再设置list的数组
public class CopyOnWriteList1 {
    public static void main(String[] args) {
        List<String> ls = new CopyOnWriteArrayList<>();
        for (int i = 0; i <100 ; i++) {

            new Thread(()->{
                ls.add(UUID.randomUUID().toString().substring(0,5));
                System.out.println(ls);
                System.out.println(ls.size());


            },String.valueOf(i)).start();
        }




    }
}
     //他的add源代码分析
   public boolean add(E e) {
        final ReentrantLock lock = this.lock;  //使用可重入锁
        lock.lock();
        try {
            Object[] elements = getArray(); //得到之前存的数组
            int len = elements.length;//得到之前数组长度
            Object[] newElements = Arrays.copyOf(elements, len + 1); //复制之前的object数组(为了适配传进来的泛型类型),复制到另外一个数组并长度变长1
            newElements[len] = e; //把新数组赋值
            setArray(newElements); //设置当前数组(替换掉之前的数组)
            return true; //处理完成
        } finally {
            lock.unlock(); //解锁
        }
    }
   //之前没有看过 <T>这种,可以理解为只是一个泛型函数全部用泛型操作
   public static <T> T[] copyOf(T[] original, int newLength) {
        return (T[]) copyOf(original, newLength, original.getClass());
    }
      //代表用了T和U的泛型,-_-看不懂先跳过
   public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
        @SuppressWarnings("unchecked")
        T[] copy = ((Object)newType == (Object)Object[].class)  //对比了是否有null
            ? (T[]) new Object[newLength]
            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
        System.arraycopy(original, 0, copy, 0,
                         Math.min(original.length, newLength));
        return copy;
    }

2.Set不安全 (和list没有区别) hashMap使用散列表结构

   Set<String> set =Collections.synchronizedList(new HashSet<>());
    Set<String> set =new CopyWroteArraySet(); 
   //HashSet的底层实现是HashMap ,因为map是不可重复的,所以set放入的值00不重复
   //源代码
    public HashSet() {
        map = new HashMap<>();
    }
     //装载因子0.75
      public HashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
    }   
    //
   public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true); //对key进行hash计算
    }

   原码(反码,补码):00000000 00000000 00000000 00000010
          右移一位(最左边一位添0)
      结果: 2
   原码(反码,补码):00000000 00000000 00000000 00000001
      结果:1
  //为了避免hash碰撞,无符号右移(二进制忽略正负号),异或 ^ 是不相同的就为1 比如 1^1=0 1^0=1
 static final int hash(Object key) {
        int h;    //key为空 hash为0,
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

3.Map也不安全(最大容量16和默认加载因子0.75)

   //企业不用 Map m=new HashMap(); //而使用下面代码,去看源码
   Map<String,String> map =new ConcurrentHashMap<>(); //用了 synchronized 同步锁

4.Callable 可返回值和抛出异常方法不同 call() Runnable是run()
如图relationship请添加图片描述

//因为Thread已经设计好了,不能增加代码,所以间接使用FutureTask(Runable的实现类)创建Runable给Thread

  1. MyThread类实现 Callable 修改call()的返回值为Integer
  2. 运行main
        MyThread thread=new MyThread();
        FutureTask ft=new  FutureTask(thread); //这个是为了Thread程序拓展增加的类
        new Thread(futureTask,"a").start();
          new Thread(futureTask,"b").start();//坑 会有缓存,之前的结果
        //得到返回值
           Interger o=(Integer)ft.get();//可能产生阻塞,最好放最后一行,或者异步通信
       public class CallableTest {
    public static void main(String[] args) {
        FutureTask<String> stringFutureTask = new FutureTask<>(new MyCallable());

        Thread thread = new Thread(stringFutureTask);
        thread.start();
        String s = null;
        try {
            s = stringFutureTask.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        System.out.println(s);
    }
}

class MyCallable implements Callable<String>{

    @Override
    public String call() throws Exception {
        return "aaa";
    }

}

-----------必须要学会的工具----------

5.CountDownLatch 是一个减法计数器 latch门栓
//用在必须要执行的任务上,6个学生全部出教室才关门
CountDownLatch count=new CountDownLatch(6);
//多线程时候 数量-1
count.countDown();
count.await();//等待计数器归0才向下执行

public class CountDownLatch1 {
    public static void main(String[] args) {
        CountDownLatch countDownLatch = new CountDownLatch(6);
        for (int i = 0; i < 6; i++) {
            new Thread(()->{

                countDownLatch.countDown();
                System.out.println("after"+countDownLatch.getCount());

            }).start();
        }
        try {
            //全部执行完,才执行这里,可以用在执行指定的任务个数后关闭连接
            countDownLatch.await();
            System.out.println("全部出去了");
                    
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

6.CyclicBarrier是一个加法计数器,还可以完成后执行一个线程
//集齐7颗龙珠召唤神龙

 CyclicBarrier cyc=new CyclicBarrier(7,()->{sout("召唤神龙成功")}); 
for(int i=1;i<=7;i++){
                 //lambda拿不到i的值,因为它本身是一个类,需要final变量才能拿到
             final int temp=i;
             new Thread(()->{
                     cyc.await(); //每执行一次+1,没有达到数量不执行结果
                    
               }).start()l
          }
  //执行结果 先执行 集齐七龙珠释放神龙 后执行线程的东西,

7.信号量 Semaphore 抢3个车位,先抢到acquire后等待,后释放
作用:多个共享资源互斥的使用,并发限流,控制最大的线程数

   Semaphore sm= new Semaphore(3);
      fori6
           new Thread(()->{
                    sm.acquire();//如果满了其他线程等待
                    TimeUnit.SECONDS.sleep(2);
                   finally{
                            sm.release();//释放;信号量+1,唤醒等待线程
                        }
            })
      public class Semaphore1 {
    public static void main(String[] args) {
        Semaphore sm = new Semaphore(3);//限制有3个线程进入,如果其中有线程退出,其他线程立即可以加入,做限流
        for (int i = 0; i < 6; i++) {
            new Thread(()->{



                try {
                    sm.acquire();//信号量满等待
                    System.out.println(Thread.currentThread().getName()+"抢到车位");
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    sm.release();//信号量+1 其他线程可以进来
                }



            }).start();

        }
    }
}

8.ReadWriteLock读写锁 (读可以多个线程读[共享锁],写只能一个线程写[独占锁]) 可重入锁的一种

   //自定义缓存  读-读可以共存 读-写不能共存 写-写不能共存
     private volatile Map<String,Object> map=new HashMap<>();
       //读写锁可以更细粒度的控制 可以提高程序性能
     private ReadWriteLock readWriteLock=new ReenrantReadWriteLock();
          //和普通的与普通的ReentrantLock()区别,可以细粒度控制读写分离
         //写的方法
            readWriteLock.writeLock().lock
         try{ //业务
         }finally{ readWriteLock.writeLock().unlock();}
         //读的方法 ,可以乱序访问
	 readWriteLock.readLock().lock
           try{ 
           //业务
           }finally{ readWriteLock.readLock().unlock();}

9.阻塞队列 FIFO (和List和Set同级 不是新东西)

图与Collection的关系
Deque双端队列(两边可以插入)
AbstractQueue非阻塞队列

请添加图片描述

  1. 什么是阻塞?
    写入(put):如果队列满了,必须阻塞等待
    取(pop):如果队列是空的必须阻塞生产

  2. 四组api (工作经常使用,根据需求使用)

    1. 全部抛出异常的方法(加入超过长度和取为空)
      ArrayBlockingQueue q = new ArrayBlockingQueue<>(3);
      q.add(“a”);
      q.add(“b”);
      q.add(“c”);
      boolean d = q.remove(“d”);//删除不存在的不会报错,返回删除结果
      q.remove(“a”);
      q.remove(“b”);
      q.remove(“c”);
      try{
      System.out.println(q.element());//取队首元素,可以判断队首是否为空
      }catch (Exception e){
      System.out.println(“队列为空”);
      }

    //不抛出异常的方法,返回boolean值,放和取都是返回boolean值,全部方法不抛出异常
    ArrayBlockingQueue q = new ArrayBlockingQueue(3);
    q.offer(“10”);
    q.offer(“20”);
    q.offer(“30”);
    System.out.println(“队首元素”+q.peek());
    String poll = q.poll();

    String poll1 = q.poll();
    System.out.println(poll);
    System.out.println(poll1);
    if (poll==null){
    System.out.println(“队列为空”);
    }
    //阻塞等待, 没有元素还是拿超元素,都会一直等待,可能会让程序崩溃 put() take() ArrayBlockingQueue q = new ArrayBlockingQueue(3);
    new Thread(()->{
    try {
    Thread.sleep(3000);
    q.put(“20”); //队列等待的时候给新的值使他继续执行
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }).start();
    try {
    q.put(“10”);
    String take = q.take();
    System.out.println(take);
    String take1 = q.take();
    System.out.println(take1);

    } catch (InterruptedException e) {
    e.printStackTrace();
    }

    //等待超时 如队列阻塞,超过时间就不等待了直接退出
    q= new ArrayBlockingQueue<>(3);
    q.offer(“a”,2,TimeUnit.SECOND);//放. 放和取都是返回boolean
    q.poll(2,TimeUnit.SECOND);//取

-------完整代码------

  public class BlockingQueueWaitingTimeUniteAndLeave {
    public static void main(String[] args) {
        ArrayBlockingQueue<String> q = new ArrayBlockingQueue<String>(3);
        new Thread(()->{
            try {
                Thread.sleep(1000);
                q.put("20");  //队列等待的时候给新的值使他继续执行
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        try {
            q.offer("10",2, TimeUnit.SECONDS);
            String poll = q.poll();
            System.out.println(poll);
            String poll1 = q.poll(2, TimeUnit.SECONDS);
            System.out.println(poll1); //null


        } catch (InterruptedException e) {
            e.printStackTrace();
        }


    }
}

10.SynchronousQueue同步队列 没有容量(不存储元素)(只有一个容量) 进去一个元素,必须取后才能重新放入元素 put() take()

public class SynchronousQueueDemo {
    public static void main(String[] args) throws InterruptedException {
        SynchronousQueue<String> q = new SynchronousQueue<String>();
//        System.out.println(q.take());,主线程不能测试,必须要在开启新线程才能测试

//
            new Thread(()->{
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                String take = null;
                try {
                    q.put("aa");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(take);
            }).start();

        new Thread(()->{
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            try {
                String take1 = q.take();
                System.out.println(take1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }).start();

    }
}

11.线程池(重点) 使用了阻塞队列

  1. 池化技术 线程池 jdbc连接池 内存池 对象池 不用销毁和创建,用完资源还给我,不用创建直接拿

  2. 优化了什么?
    减低资源消耗
    提高响应速度
    方便管理

  3. 使用 alibaba开发手册 强制线程池不允许使用Executors(但是很多公司使用它)创建(指定了max为21亿个线程,会OOM异常),而是使用ThreadPoolExecutor直接去创建
    //下面几种方式,都可能会OOM
    threadPool=Executors.newSingleThreadExecutor();//创建单线程
    .newFixedThreadPool(5);//固定大小的线程池
    .newCachedThreadPool();//可伸缩的,遇强则强,遇弱则弱
    try{
    fori
    threadPool.execute(()->{
    // sout线程名可看多少个线程
    //在这里执行业务代码
    });

    }finally{
    //关闭线程池
    threadPool.shutdown();
    }
    ------完整代码-------

public class ExecutorDemo {
    public static void main(String[] args) {
        ExecutorService thread = Executors.newSingleThreadExecutor();
        ExecutorService thread1 = Executors.newFixedThreadPool(2000000000);
        ExecutorService thread3 = Executors.newCachedThreadPool();
//
//        for (int i = 0; i < 10; i++) {
//           thread.execute(()->{
//               System.out.println("你好"+Thread.currentThread().getName());
//           });
//        }
//        for (int i = 0; i < 10; i++) {
//            thread1.execute(()->{
//                System.out.println("你好"+Thread.currentThread().getName());
//            });
//        }
        for (int i = 0; i < 1000000000; i++) { //不要测试,电脑直接黑屏,声明Cached会导致系统奔溃,创建太多线程
            thread3.execute(()->{
                System.out.println("你好"+Thread.currentThread().getName());
            });
        }
    }
}
  1. ThreadPoolExecutor7大参数
    阻塞队列
    工厂

  2. 代码

     ExecutorService threadPool=new ThreadPoolExecutor(
2,  //core核心大小(正常可以处理的情况使用多少线程) 
                        5, //max(core处理不过来需要扩大线程数)   
                        3, //   keepAliveTime超时等待时间(如果多出来的max-core数没有被使用,等待关闭的时间)         
                        TimeUnit.SECONDS, // keep等待的时间单位
                        new LinkedBlockingDeque(3), //双端队列
                        Executors.defaultThreadFactory(),//工厂
                        new ThreadPoolExecutor.DiscardOldestPolicy() //  拒绝策略 //4个,如果线程池满了不能处理后的操作  
        );  //   当前使用线程大小=max+阻塞队列的长度
        //拒绝策略详细解释
           new ThreadPoolExecutor.DiscardOldestPolicy()//,如果最老的线程还在被占用,则抛弃,否则使用他
                                                   .Discard();//如果线程不够用了,直接抛弃
                                                   .CallerRunsPolicy(); //哪里来的线程回哪里去处理 可能main处理
                                                   .AbortPolicy();//不处理直接抛出异常

----完整代码----

public class LocalThread {
    public static void main(String[] args) {
  int max=Runtime.getRuntime().availableProcessors();
        ThreadPoolExecutor thread = new ThreadPoolExecutor(
                3,
                max,
                2,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(3),
               Executors.defaultThreadFactory(),
//                new ThreadPoolExecutor.AbortPolicy()
//                new ThreadPoolExecutor.CallerRunsPolicy()
//                new ThreadPoolExecutor.DiscardPolicy()  //多出来的线程不执行
                new ThreadPoolExecutor.DiscardOldestPolicy()  //去找执行完的线程 如果没有抛弃任务

        );
        for (int i = 0; i < 100; i++) {
            thread.execute(()->{
                System.out.println(Thread.currentThread().getName());

            });
        }


    }
}

12.最大线程如何定义?(调优)

  1. 分类
    1. CPU密集型(): 逻辑核数 ,通过代码可以获得核数>Runtime.getRuntime().availableProcessors()
    2. IO密集型 全部线程数-判断你的程序十分耗IO资源的线程数

13.四大函数式接口(必须掌握)
新时代程序员: jdk8新特性 lambda表达式 链式编程 函数式接口 Stream流式计算

  1. 函数式接口(只有一个方法的接口) 超级多的在代码底层存在,简化编程模型,新版本框架底层大量使用
    //自带foreach()方法 ,接口上面定义这个注解
    @FunctionalInterface
  2. 四大函数
          //有个
           Function<String,String> function=new Function<String,String>(){
                  public String apply(){return str){return str}} //看源码,第二个参数是返回的类型
          };
         //lambda简化
           Function<String,Integer> function=(str)->{return 1;}
         sout(function.apply("aaa")); //返回1,进入什么返回什么


    //断定性接口(一个函数返回boolean) 
         //普通写法
  Predicate<String> stringPredicate = new Predicate<String>() {
        @Override
        public boolean test(String s) {
            return s.isEmpty();
        }
    };
         //lambda简化后,好方便
         Predicate<String> predicate=(str)->{return str.isEmpty()};//判断字符串是否为空
           sout(predicate.test("aa")); //false
  1. 补充了默认方法,默认方法可以在接口写 具体的实现 代码如下 实现类不用实现默认方法
      public class TestDefault implements MyInterface {

    @Override
    public int size() {
        // TODO Auto-generated method stub
        return 1;
    }

    public static void main(String[] args) {
        TestDefault testDefault = new TestDefault();
        MyInterface.getInfo(testDefault.size(), testDefault.isEmpty());
    }

}
// 函数式接口
interface MyInterface {
    // 抽象方法
    int size();

    // 默认方法
    default boolean isEmpty () {
        return size() == 0;
    }

    // 静态方法
    static void getInfo(int size, boolean isEmpty) {
        System.out.println("size is " + size + ", empty: " + isEmpty);
    }

}

13.Consumer(消费者没有返回值只有输入)和Supplier(没有参数只有返回值 提供者)接口
//消费者类似于 一块石头丢入大海,杳无音信,被消费了
//提供者类似于 我调用方法就可以拿到我的东西

Consumer<String> objectConsumer = (str)->{
    System.out.println("已经消费没有返回值");
};
objectConsumer.accept("aaa");
//lambda返回值是根据你方法里面返回的类型自动判断的
Supplier<String> supplier = ()->{return "aa";};
String s = supplier.get(); 
System.out.println(s); //"aa"

14.Stream流式计算(必须掌握) 大数据: 集合就是存储 +计算交给流
//用一行代码,选择有5个用户,筛选出 id为偶数 年龄大于12岁 用户名转为大写 用户名倒着排序 只输出一个用户

User ls = new User(1, 21, "ls");
User sz = new User(3, 12, "sz");
User dz = new User(4, 50, "dz");
User zs = new User(2, 27, "zs");
User qq = new User(5, 10, "qq");
List<User> list = Arrays.asList(ls, sz, dz, zs, qq);
list.stream()
    .filter(u->{return u.getId()%2==0;})
    .filter(u->{return u.getAge()>12;})  //过滤
    .map(u->{return u.getName().toUpperCase();}) //过滤出 返回的值
   .sorted((uu1,uu2)->{return uu2.compareTo(uu1);}) //从小到大排序,自己在实体类写对比id
   .limit(1)  //分页
   .forEach(System.out::printLn); //输出  ZS

15.ForkJoin(中级) jdk1.7 并行执行任务提供效率,大数据量(mapreduce大任务拆分成小任务的思想)时使用

1.特点 工作窃取 (另外一个任务完成了可以窃取其他任务的子任务) 都是双端队列

    //求和demo,相当于递归实现,并且拆分任务递归
public class ForkJoinWork extends RecursiveTask<Long> { //继承了递归任务实现了方法
    private Long start;//起始值
    private Long end;//结束值
    public static final Long critical = 10000L;//临界值
    public ForkJoinWork(Long start, Long end) {
        this.start = start;
        this.end = end;
    }
@Override
protected Long compute() {
    //判断是否是拆分完毕
    Long lenth = end - start;
    if(lenth<=critical){
    //如果拆分完毕就相加
    Long sum = 0L;
    for (Long i = start;i<=end;i++){
    sum += i;
    }
    return sum;
    }else {

        //没有拆分完毕就开始拆分
        Long middle = (end + start)/2;//计算的两个值的中间值
        ForkJoinWork right = new ForkJoinWork(start,middle);
        right.fork();//拆分,并压入线程队列
        ForkJoinWork left = new ForkJoinWork(middle+1,end);
        left.fork();//拆分,并压入线程队列
        // //合并小任务和合并结果,相当于一颗递归树
        //先将任务拆分为小任务,然后从树低到树顶合并执行任务结果
        return right.join() + left.join();
    }
  }
}
public class ForkJoinWorkDemo {
    public static void main(String[] args) throws ExecutionException,
            InterruptedException {
        test(); //15756 // 14414 // 203
    }
    public static void test() throws ExecutionException,
            InterruptedException {
//ForkJoin实现
        long l = System.currentTimeMillis();
        ForkJoinPool forkJoinPool = new ForkJoinPool();//实现ForkJoin 就必须有ForkJoinPool的支持
        ForkJoinTask<Long> task = new ForkJoinWork(0L,10000001L);//参数为起始值与结束值
        ForkJoinTask<Long> result = forkJoinPool.submit(task);
        Long aLong = result.get();
        long l1 = System.currentTimeMillis();
        System.out.println("invoke = " + aLong +" time: " + (l1-l));
    }
    public static void test2(){
//普通线程实现
        Long x = 0L;
        Long y = 2000000000L;
        long l = System.currentTimeMillis();
        for (Long i = 0L; i <= y; i++) {
            x+=i;
        }
        long l1 = System.currentTimeMillis();
        System.out.println("invoke = " + x+" time: " + (l1-l));
    }
    public static void test3(){
//Java 8 并行流的实现 (高级)
        long l = System.currentTimeMillis();
        long reduce = LongStream.rangeClosed(0,
                2000000000L).parallel().reduce(0, Long::sum);
        long l1 = System.currentTimeMillis();
        System.out.println("invoke = " + reduce+" time: " + (l1-l));
    }
}
//代码运行模拟,但是没有模拟出递归 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/628582.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

瑞吉外卖业务开发

数据库 我电脑上的数据库登录指令&#xff1a;mysql -uroot -p123456常用指令&#xff1a;show databases、user 数据库名、show tables。 创建项目 创建完项目后&#xff0c;要及时检查maven仓库的配置&#xff0c;jdk的配置&#xff0c;项目的编码&#xff0c;如下图。 配…

数据同步智能化!利用ETLCloud自动化流程实现钉钉OA系统数据自动同步至数仓

钉钉数据同步需求 钉钉是一款企业级通讯和协同办公应用软件&#xff0c;钉钉为企业提供包括聊天、通讯录、日程安排、考勤打卡、审批、通知公告、文件共享、会议等功能&#xff0c;很多企业都在使用钉钉。 很多情况下我们需要把钉钉的数据拉取到数据库中&#xff0c;然后再通…

案例分享 | 汽车连接器焊锡质量检测

连接器是电脑、电视、汽车等常见产品中不可缺少的部件&#xff0c;主要由接触件、绝缘体与金属壳体组成&#xff0c;用于传输电流或信号。 汽车连接器约占全球连接器市场四分之一的份额&#xff0c;随着未来汽车产业的持续膨胀&#xff0c;市场前景广阔。连接器产品的微型化、…

RPC通用爬虫

文章目录 RPC通用爬虫一、项目案例二、Rpc原理解析三、Rpc代码分享四、自我总结 RPC通用爬虫 一、项目案例 测试网址: aHR0cDovL3d3dy5mYW5nZGkuY29tLmNuL3NlcnZpY2UvYnVsbGV0aW5fbGlzdC5odG1sP3R5cGVhPWI2N2MzYjhhZGJkY2U3NGQ 二、Rpc原理解析 图解关系: ​ 主要包括,爬虫程…

Dockerfile应用的容器化

文章目录 Dockerfile应用的容器化应用的容器化——简介应用的容器化——详解单体应用容器化获取应用代码分析Dockerfile容器化当前应用/构建具体的镜像推送镜像到仓库运行应用程序测试总结 最佳实践利用构建缓存合并镜像 命令总结 Dockerfile应用的容器化 Docker 的核心思想是…

为什么网络安全缺口大,招聘却很少?

2023 年我国网络空间安全人才数量缺口超过了 140 万&#xff0c;就业人数却只有 10 多万&#xff0c;缺口高达了 93%。这里就有人会问了&#xff1a; 1、网络安全行业为什么这么缺人&#xff1f; 2、明明人才那么稀缺&#xff0c;为什么招聘时招安全的人员却没有那么多呢&am…

头部大模型公司进京赶考,向量数据库成为应考神器

日前&#xff0c;由品玩主办的「模型思辨」国内大模型产业生态研讨会在北京举办&#xff0c;Zilliz 与 360 集团、阿里巴巴、昆仑万维等来自大模型产业链的头部公司及投资机构参会&#xff0c;会上 Zilliz 创始人兼首席执行官星爵、360 集团创始人周鸿祎、昆仑万维创始人方汉等…

C++ 类设计的实践与理解

前言 C代码提供了足够的灵活性&#xff0c;因此对于大部分工程师来说都很难把握。本文介绍了写好C代码需要遵循的最佳实践方法&#xff0c;并在最后提供了一个工具可以帮助我们分析C代码的健壮度。 1. 尽可能尝试使用新的C标准 到2023年&#xff0c;C已经走过了40多个年头。新…

如何进行微服务测试?

微服务测试是一种特殊的测试类型&#xff0c;因为它涉及到多个独立的服务。以下是进行微服务测试的一般性步骤&#xff1a; 1. 确定系统架构 了解微服务架构对成功测试至关重要。确定每个微服务的职责、接口、依赖项和通信方式。了解这些信息可以帮助您更好地规划测试用例和测…

day09——线性回归

线性回归 一、什么是线性回归1&#xff0c;定义与公式2&#xff0c;线性回归的特征与目标的关系 二、线性回归的损失和优化原理1&#xff0c;损失函数2&#xff0c;优化算法 三、API四、实操&#xff1a;波士顿房价预测1&#xff0c;数据来源&#xff1a;scikit-learn2&#xf…

Acgis中实现栅格经纬度和行政区关联

写在前面 我是一个Acgis小白&#xff0c;写这篇博客是为了记录完成过程&#xff0c;如果有更高效的办法欢迎分享~ 我用的是Arcgis10.2。 需求描述 目前已有意大利的shp文件&#xff0c;希望将意大利划分成0.1*0.1经纬度的栅格&#xff0c;并且关联每个栅格中心点所属的省份信…

DBeaver复制数据库(数据库表结构以及内容)

一、 首先先建立一个数据库 &#xff08;已有请忽略此步骤&#xff09; &#xff08;名字 字符集等按需要自己填写&#xff09; 二、选择要复制的数据库 2.1右键选择 工具->转储数据库 2.2选择要导出的数据 2.3 选择要导出的路径 2.4 点击开始&#xff0c;等待导出完…

Revit中绘制弯曲的靠背栏杆和生成过梁

一、Revit中怎么绘制弯曲的靠背栏杆 栏杆通常我们见过位于在阳台处&#xff0c;但是在我们的古建筑中很常见到一种靠背栏杆&#xff0c;例如凉亭里面就很常见这种栏杆。那么如何绘制呢? 利用公制栏杆——支柱进行绘制 要运用放样工具进行绘制&#xff0c;设置一个工作平面&…

中国电子学会2023年05月份青少年软件编程Scratch图形化等级考试试卷四级真题(含答案)

2023-05 Scratch四级真题 分数&#xff1a;100 题数&#xff1a;24 测试时长&#xff1a;90min 一、单选题(共10题&#xff0c;共30分) 1. 下列积木运行后的结果是&#xff1f;&#xff08;B&#xff09;&#xff08;说明&#xff1a;逗号后面无空格&#xff09;&#xff…

mysql join 与 拆分成单表查询如何选择

参考以下文章&#xff0c;不错 数据库联表查询时&#xff0c;是直接使用join好还是分别查询到数据后自己处理较好&#xff1f; - 知乎 一&#xff0c;声明 1&#xff0c;数据量 首先场景是多个表数据量比较大&#xff0c;可能达到百万级 2&#xff0c;结论&#xff1a;最…

springboot项目启动指定对应环境的方法

1. 多环境准备 今天教大家一种多环境profile的写法&#xff0c;当然也可创建多个yml文件。如下所示&#xff1a; spring:application:name: cms-discovery-eureka-ha --- # 区分多环境 spring:profiles: peer1 server:port: 9092 eureka:in…

十、ELK安装ElastAlert 2插件飞书机器人告警(docker)

实现效果 1.创建相应挂载目录和文件 可任意位置&#xff0c;挂载对上就行&#xff0c;方便直接在宿主机修改配置。 /data/feishu-alert/config.yaml /data/feishu-alert/rules 2.编写config.yaml配置文件(/data/feishu-alert/config.yaml) #指定告警文件存放目录 rules_fo…

从C语言到C++_16(list的介绍和常用接口函数)

目录 1. list 介绍和简单使用 1.1 list介绍 1.2 list简单接口函数 1.3 push_back 和遍历 1.4 list常规接口函数使用 2. list 的其它接口函数 2.1 splice 接合 2.2 remove 删完一个值 2.3 sort和reverse 本章完。 list是个双向带头循环链表。 带头双向循环链表我们在…

21份软件测试全流程文档模板(标准版)

1、需求说明书 2、功能测试计划 3、功能测试用例 4、业务流程测试用例 5、系统安装配置说明书 6、阶段功能测试报告 7、性能测试计划 8、性能测试用例 9、性能测试报告 10、系统功能测试报告 11、需求变更说明书 12、用户建议说明书 13、验收测试报告 14、产品发布说明书 15、系…

redis下载安装

本文主要介绍如果在Centos7下安装Redis。 1.安装依赖 redis是由C语言开发&#xff0c;因此安装之前必须要确保服务器已经安装了gcc&#xff0c;可以通过如下命令查看机器是否安装&#xff1a; <span style"color:#000000"><span style"background-c…