JUC——并发编程—第二部分

集合类不安全

list不安全


//报错 java.util.ConcurrentModificationException
public class ListTest  {public static void main(String[] args) {List<String>  list= new CopyOnWriteArrayList<>();//并发下Arrayist边读边写会不安全的/*** 解决方案:* 1.List<String>  list= new Vector<>();* 2.List<String>  list= Collections.synchronizedList(new ArrayList<>());* 3.List<String>  list= new CopyOnWriteArrayList<>();*/for(int i=0;i<50;i++){new Thread(()->{list.add(UUID.randomUUID().toString().substring(0,5));System.out.println(list);},String.valueOf(i)).start();}}
}

上面这个多个线程边读边写时会出现如下报错

java.util.ConcurrentModificationException

在CopyOnWriteArrayList的底层用一个这样的数据实现

volatile内存,模型中规定保证线程间的可见性,但不保证原子性

CopyOnWrite使用的是lock锁,Vertor使用的是synchronized,有sync都会很慢。

list的解决方案有使用vector这个安全类和工具类和 juc.

工具类是将其变成synchronized,但很慢,juc是用写入时复制。

Set不安全

set和List是一个同级的关系,都是Collection的子类。

所以set在边读边写时也会有java.util.ConcurrentModificationException报错。

但是set没有vector,只有工具类和juc的解决方案。

public class SetList {public static void main(String[] args) {Set<String> set = new HashSet<>();
//        Set<String> set = Collections.synchronizedSet(new HashSet<>());
//        Set<String> set = new CopyOnWriteArraySet<>();for(int i=0;i<50;i++){new Thread(()->{set.add(UUID.randomUUID().toString().substring(0,5));System.out.println(set);},String.valueOf(i)).start();}}
}

hashset底层就是hashmap。

hashset的add方法就是hashmap的put方法。

map不安全

这个也有" java.util.ConcurrentModificationException报错

 这里的解决方案是juc下的ConcurrentHashMap。

public class MapList {public static void main(String[] args) {//加载因子,初始化容量 0.75和16
//        Map<String,String> map=new HashMap<>();Map<String,String> map=new ConcurrentHashMap<>();for(int i=0;i<50;i++){new Thread(()->{map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0,5));System.out.println(map);},String.valueOf(i)).start();}}
}

走进Callable

callable接口就类似于runnable接口,然而runnable接口不会返回结果也不会抛出异常,callable就可以。一个是call()方法,一个是run()方法.

callable接口需要提供一个泛型,泛型的参数等于方法的返回值。 

如何用new Thread().start接收callable接口并开启线程

Thread()只能接收runnable参数,不认识callable()参数,所以callable要通过runnable去做一个桥梁,在runnable里面有如下的一些实现。

其中FutureTask这个实现类与Callable有联系,如下所示,有一个构造参数就是Callable<V>

这里用到的应该就是适配器模式,这里的futuretask就是一个适配器。

1.两个同样的callable实现类开启的线程内的输出结果会被缓存。

2.结果可能会等待,会阻塞。


public class CallavkeTest {public static void main(String[] args) throws ExecutionException, InterruptedException {//   new Thread(new Runnable()).start();  //传统方式
//         new Thread(new FutureTask<V>()).start();
//         new Thread(new FutureTask<V>(Callable)).start();mythread mythread=new mythread();   //callable接口的实现类FutureTask futureTask = new FutureTask(mythread);        //callable接口的适配类new Thread(futureTask,"A").start();new Thread(futureTask,"B").start();  //只会输出一个call,结果被缓存了,达到提高效率的目的String str=(String)futureTask.get(); //获取callable的返回结果,get方法会等待结果,可能产生阻塞,要将其放在最后//或者通过异步通信来处理!System.out.println(str);}
}class mythread implements Callable<String> {@Overridepublic String call() throws Exception {System.out.println("call方法被调用");//耗时操作return "1230";}
}//class mythread implements Runnable{
//
//    @Override
//    public void run() {
//
//    }
//}

 

常用的辅助类

CountDownLatch

原理: 

countDownLatch.countDown(); //-1

countDownLatch.await(); //等待计数器归零再向下执行

//计数器
public class CountDownLatchDemo {public static void main(String[] args) throws InterruptedException {//总数是6CountDownLatch countDownLatch = new CountDownLatch(6);for(int i=0;i<6;i++){new Thread(()->{System.out.println(Thread.currentThread().getName()+"go out");countDownLatch.countDown(); //-1},String.valueOf(i)).start();}countDownLatch.await(); //等待计数器归零再向下执行System.out.println("Close door");
//        countDownLatch.countDown(); //-1}
}

CyclicBarrier

加法计数器

 有两种构造参数,一个是传个计数,一个是传个计数完之后要执行的线程。


public class CyclicBarrierDemo {public static void main(String[] args) {CyclicBarrier cyclicBarrier=new CyclicBarrier(7,()->{System.out.println("g盖亚!!!");});for(int i=0;i<7;i++){final int temp=i;//lamda表达式能操作到i吗?new Thread(()->{System.out.println(Thread.currentThread().getName()+"收集"+temp+"个"); //间接获得try {cyclicBarrier.await();  //等待} catch (InterruptedException e) {throw new RuntimeException(e);} catch (BrokenBarrierException e) {throw new RuntimeException(e);}}).start();}}
}

如果计数为8但是线程只有7个的话,就会永远卡死在一个地方。 

Semaphore(信号量)

这个 的实现也有两种参数

public class SemaphoreDemo {public static void main(String[] args) {//线程数量:停车位Semaphore semaphore = new Semaphore(3);for(int  i=1;i<=6;i++){new Thread(()->{//acquire()得到try {semaphore.acquire();System.out.println(Thread.currentThread().getName()+"抢到车位");TimeUnit.SECONDS.sleep(2);System.out.println(Thread.currentThread().getName()+"离开车位 ");} catch (InterruptedException e) {throw new RuntimeException(e);}finally {//realease() 释放semaphore.release();}},String.valueOf(i)).start();}}
}

一开始只有三个进去了,后面三个都出去了,后三个才能进来,这里的主要应用场景就是限流。 

原理:

semaphore.acquire();  //获取,假设已经的满了,就等待到资源被释放为止。

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

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

读写锁

readwritelock只有一个实现类,可重入的读写锁. 读的时候可以多个线程同时读,但是写的时候只能一个线程在写。

如下所示的一个自定义缓存类读写操作

/*** readwritelock*/
public class readwritelockdemo {public static void main(String[] args) {MyCache  myCache=new MyCache();//写入for(int i=0;i<5;i++){final int temp=i;new Thread(()->{myCache.put(temp+"",temp+"");},String.valueOf(i)).start();}//读取for(int i=0;i<5;i++){final int temp=i;new Thread(()->{myCache.get(temp+"");},String.valueOf(i)).start();}}
}/*** 自定义缓存*/
class MyCache{private volatile Map<String,Object> map=new HashMap<>();//存入public void put(String key,Object value){System.out.println(Thread.currentThread().getName()+"写入"+key);map.put(key,value);System.out.println(Thread.currentThread().getName()+"写入完毕");}//读取public void get(String key){System.out.println(Thread.currentThread().getName()+"读取"+key);Object o=map.get(key);System.out.println(Thread.currentThread().getName()+"读取完毕");}
}

输出如下,在一个线程写入的过程中另一个线程也在写入,这种情况是不能发生的

使用了读写锁之后,写操作只会允许一个线程执行,读操作则会有多个线程同时进行.。


/*** readwritelock*/
public class readwritelockdemo {public static void main(String[] args) {
//        MyCache  myCache=new MyCache();MyCacheLock myCacheLock=new MyCacheLock();//写入for(int i=0;i<5;i++){final int temp=i;new Thread(()->{myCacheLock.put(temp+"",temp+"");},String.valueOf(i)).start();}//读取for(int i=0;i<5;i++){final int temp=i;new Thread(()->{myCacheLock.get(temp+"");},String.valueOf(i)).start();}}
}
/*** 加上锁之后*/
class MyCacheLock{private volatile Map<String,Object> map=new HashMap<>();//读写锁,可以更加细力度的控制private ReadWriteLock readWriteLock=new ReentrantReadWriteLock();//存入,只有一个线程写public void put(String key,Object value){readWriteLock.writeLock().lock();try{System.out.println(Thread.currentThread().getName()+"写入"+key);map.put(key,value);System.out.println(Thread.currentThread().getName()+"写入完毕");}catch (Exception e){e.printStackTrace();}finally {readWriteLock.writeLock().unlock();}}//读取,所有线程都能读public void get(String key){readWriteLock.readLock().lock();try{System.out.println(Thread.currentThread().getName()+"读取"+key);Object o=map.get(key);System.out.println(Thread.currentThread().getName()+"读取完毕");}catch (Exception e){e.printStackTrace();}finally {readWriteLock.readLock().unlock();}}
}

阻塞队列

JUC有这样一个阻塞队列的接口,t它的实现有一个SynchronousQueue同步队列,还有一些数组阻塞队列,和链表阻塞队列等等

可以看见Queue和List和Set是同一级别的,在Queue接口下有这个BlockingQueue接口和Deque和AbstractQueue。

 典型使用场景: 多线程并发处理,线程池,生产者消费者。

阻塞队列四组API

1.抛出异常2.不会抛出异常3.阻塞等待4.超时等待

方式抛出异常有返回值,不抛出异常阻塞等待超时等待
添加addoffer()put()offer()
移除removepoll()take()poll()
检测队首元素elementpeek
public class Test {public static void main(String[] args) throws InterruptedException {
//        test1();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"));//Exception in thread "main" java.lang.IllegalStateException: Queue full
//        blockingQueue.add("d");System.out.println("_______________");System.out.println(blockingQueue.remove());System.out.println(blockingQueue.remove());System.out.println(blockingQueue.remove());//Exception in thread "main" java.util.NoSuchElementException
//        System.out.println(blockingQueue.remove());}/*** 有返回值,不抛出异常*/public static void test2(){ArrayBlockingQueue 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"));  //不抛出异常,返回falseSystem.out.println("_______________————————————————————");System.out.println(blockingQueue.poll());System.out.println(blockingQueue.poll());System.out.println(blockingQueue.poll());System.out.println(blockingQueue.poll());  //也不抛出异常,返回null}/*** 等待,阻塞(一直阻塞)*/public static void test3() throws InterruptedException {ArrayBlockingQueue 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 {ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);blockingQueue.offer("a");blockingQueue.offer("b");blockingQueue.offer("c");blockingQueue.offer("d",2, TimeUnit.SECONDS); //超时时间和单位System.out.println(blockingQueue.poll());System.out.println(blockingQueue.poll());System.out.println(blockingQueue.poll());System.out.println(blockingQueue.poll(2, TimeUnit.SECONDS));}
}

 

同步队列SynchronousQueue

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

/*** 同步队列*/
public class SynchronousQueueDemo {public static void main(String[] args) {SynchronousQueue<String> blockingQueue = new SynchronousQueue<>();//同步队列new Thread(()->{try {System.out.println(Thread.currentThread().getName()+"put 1");blockingQueue.put("1");System.out.println(Thread.currentThread().getName()+"put 2");blockingQueue.put("2");System.out.println(Thread.currentThread().getName()+"put 3");blockingQueue.put("3");} catch (InterruptedException e) {throw new RuntimeException(e);}},"t1").start();new Thread(()->{try {TimeUnit.SECONDS.sleep(3);System.out.println(Thread.currentThread().getName()+"=>"+blockingQueue.take());TimeUnit.SECONDS.sleep(3);System.out.println(Thread.currentThread().getName()+"=>"+blockingQueue.take());TimeUnit.SECONDS.sleep(3);System.out.println(Thread.currentThread().getName()+"=>"+blockingQueue.take());} catch (InterruptedException e) {throw new RuntimeException(e);}},"t2").start();}
}

线程池(重点)

线程池:三大方法,7大参数,4中拒绝策略。

池化技术:事先准备好资源,来人就用,用完放回。

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

线程池,连接池,内存池,对象池。

线程池的好处:

1、降低资源的消耗

2、提高响应的速度

3、方便管理。

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

线程的三大方法

//Executors 工具类、三大方法。
public class Demo01 {public static void main(String[] args) {
//        ExecutorService threadPoll = Executors.newSingleThreadExecutor();//单个线程
//        ExecutorService threadPoll =Executors.newFixedThreadPool(5); //创建一个固定线程池的大小ExecutorService threadPoll =Executors.newCachedThreadPool(); //可伸缩try {for(int i=0;i<10;i++){//使用了线程池后,使用线程池创建线程threadPoll.execute(()->{System.out.println(Thread.currentThread().getName()+"  OK");});}} catch (Exception e) {throw new RuntimeException(e);}finally {//线程池用完,程序结束,关闭线程池threadPoll.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,它的源码如下

 可以看见有7个参数

1.核心线程池大小2.最大核心线程池大小3.存活时间,4.超时单位5.阻塞队列6.线程工厂,用于创建线程7.拒绝策略。

    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;}

前面三个方法的前两个参数分别是1,1  5,5   0,Inter.MaxValue。(21亿大小)

因此阿里巴巴的手册里面才会这样写。

四大策略 

核心线程池大小为2,最大为5,一开始只有2个,但是阻塞队列里面满了之后又来人了会开放剩下三个,又慢了之后就不给进了,这就是拒绝策略。

等到了那三个队列空闲后后,经过了超时时间就会关闭释放。

四个实现类对应四大策略 

 自定义线程池、

拒绝策略

会抛出异常.

//Executors 工具类、三大方法。
public class Demo01 {public static void main(String[] args) {ExecutorService threadPoll =new ThreadPoolExecutor(2,5,3,TimeUnit.SECONDS,new LinkedBlockingQueue<>(3),Executors.defaultThreadFactory(),  //一般不变new ThreadPoolExecutor.AbortPolicy());  //该拒绝策略是银行满了,还有人进来时就不处理该人并抛出异常。try {for(int i=0;i<10;i++){//使用了线程池后,使用线程池创建线程threadPoll.execute(()->{System.out.println(Thread.currentThread().getName()+"  OK");});}} catch (Exception e) {throw new RuntimeException(e);}finally {//线程池用完,程序结束,关闭线程池threadPoll.shutdown();}}
}

第二策略

哪来的回哪里去,由原本的线程来执行。

//Executors 工具类、三大方法。
public class Demo01 {public static void main(String[] args) {ExecutorService threadPoll =new ThreadPoolExecutor(2,5,3,TimeUnit.SECONDS,new LinkedBlockingQueue<>(3),Executors.defaultThreadFactory(),  //一般不变new ThreadPoolExecutor.CallerRunsPolicy());  //哪来的去哪里!try {for(int i=0;i<10;i++){//使用了线程池后,使用线程池创建线程threadPoll.execute(()->{System.out.println(Thread.currentThread().getName()+"  OK");});}} catch (Exception e) {throw new RuntimeException(e);}finally {//线程池用完,程序结束,关闭线程池threadPoll.shutdown();}}
}

第三策略

队列满了不会抛出异常。会直接丢掉任务。

package com.yhy.pool;import java.util.concurrent.*;/*** new ThreadPoolExecutor.AbortPolicy());  //该拒绝策略是银行满了,还有人进来时就不处理该人并抛出异常。* new ThreadPoolExecutor.CallerRunsPolicy());  //哪来的去哪里!* new ThreadPoolExecutor.DiscardPolicy()); //队列满了就踢了并且不抛出异常。* new ThreadPoolExecutor.DiscardOldestPolicy());  //队列满了不会抛出异常,尝试去和最早的竞争,也不会抛出异常!*/
public class Demo01 {public static void main(String[] args) {ExecutorService threadPoll =new ThreadPoolExecutor(2,5,3,TimeUnit.SECONDS,new LinkedBlockingQueue<>(3),Executors.defaultThreadFactory(),  //一般不变new ThreadPoolExecutor.DiscardPolicy());  try {for(int i=0;i<10;i++){//使用了线程池后,使用线程池创建线程threadPoll.execute(()->{System.out.println(Thread.currentThread().getName()+"  OK");});}} catch (Exception e) {throw new RuntimeException(e);}finally {//线程池用完,程序结束,关闭线程池threadPoll.shutdown();}}
}

可以看见只有8条输出,有两条被踢了。

第四策略

//Executors 工具类、三大方法。
public class Demo01 {public static void main(String[] args) {ExecutorService threadPoll =new ThreadPoolExecutor(2,5,3,TimeUnit.SECONDS,new LinkedBlockingQueue<>(3),Executors.defaultThreadFactory(),  //一般不变new ThreadPoolExecutor.DiscardOldestPolicy());  //队列满了不会抛出异常,尝试去和最早的竞争,也不会抛出异常!try {for(int i=0;i<10;i++){//使用了线程池后,使用线程池创建线程threadPoll.execute(()->{System.out.println(Thread.currentThread().getName()+"  OK");});}} catch (Exception e) {throw new RuntimeException(e);}finally {//线程池用完,程序结束,关闭线程池threadPoll.shutdown();}}
}

  

CPU密集型,IO密集型(扩展)

经常会被问,池的最大大小如何去设置。

CPU密集型: 12核的CPU最多12条线程同时执行,多少核就

IO密集型:       程序 15个大型任务 IO十分占用资源 ,一般设置为两倍30个线程。

/*** new ThreadPoolExecutor.AbortPolicy());  //该拒绝策略是银行满了,还有人进来时就不处理该人并抛出异常。* new ThreadPoolExecutor.CallerRunsPolicy());  //哪来的去哪里!* new ThreadPoolExecutor.DiscardPolicy()); //队列满了就踢了并且不抛出异常。* new ThreadPoolExecutor.DiscardOldestPolicy());  //队列满了不会抛出异常,尝试去和最早的竞争,也不会抛出异常!*/
public class Demo01 {public static void main(String[] args) {//自定义线程池! 工作 ThreadPoolExecutor//最大线程池如何定义//1、CPU 密集型,几核,就是几,可以保CPu的效率最高!//2、IO密集型//      程序 15个大型任务 IO十分占用资源//获取CPU核数System.out.println(Runtime.getRuntime().availableProcessors());ExecutorService threadPoll =new ThreadPoolExecutor(2,Runtime.getRuntime().availableProcessors(),3,TimeUnit.SECONDS,new LinkedBlockingQueue<>(3),Executors.defaultThreadFactory(),  //一般不变new ThreadPoolExecutor.DiscardOldestPolicy());  //队列满了不会抛出异常,尝试去和最早的竞争,也不会抛出异常!try {for(int i=0;i<10;i++){//使用了线程池后,使用线程池创建线程threadPoll.execute(()->{System.out.println(Thread.currentThread().getName()+"  OK");});}} catch (Exception e) {throw new RuntimeException(e);}finally {//线程池用完,程序结束,关闭线程池threadPoll.shutdown();}}
}

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

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

相关文章

iPhone苹果手机复制粘贴内容提示弹窗如何取消关闭提醒?

经常使用草柴APP查询淘宝、天猫、京东商品优惠券拿购物返利的iPhone苹果手机用户&#xff0c;复制商品链接后打开草柴APP粘贴商品链接查券时总是弹窗提示粘贴内容&#xff0c;为此很多苹果iPhone手机用户联系客服询问如何关闭iPhone苹果手机复制粘贴内容弹窗提醒功能的方法如下…

Java-API简析_java.util.Objects类(基于 Latest JDK)(浅析源码)

【版权声明】未经博主同意&#xff0c;谢绝转载&#xff01;&#xff08;请尊重原创&#xff0c;博主保留追究权&#xff09; https://blog.csdn.net/m0_69908381/article/details/133463511 出自【进步*于辰的博客】 因为我发现目前&#xff0c;我对Java-API的学习意识比较薄弱…

Linux Ubuntu配置Git的方法

本文介绍在Linux操作系统的Ubuntu版本中&#xff0c;配置分布式开源版本控制系统Git&#xff0c;随后基于Git克隆GitHub中项目的代码的详细方法。 在之前的文章分布式版本控制系统Git的下载、安装与使用其复制GitHub项目代码的方法&#xff08;https://blog.csdn.net/zhebushib…

【前段基础入门之】=>你不知道的 CSS 选择器的进阶使用!

导语&#xff1a; 在上一章节中&#xff0c;我们了解了 CSS 的一些基本语法概念&#xff0c;那么在这一章节中我们就带来 CSS 选择器知识的分享&#xff0c;选择器这一章的知识点有一点多&#xff0c;不过我们只要认真去理解&#xff0c;学习它也是没什么问题的&#xff0c;还有…

【模型压缩】Distiller学习-初认识

Distiller学习-初认识 简介 Intel AILab的神经网络压缩框架&#xff0c;建立在Pytorch基础上 安装 压缩方法 权重正则化方法权重剪枝方法训练后量化方法训练时量化方法条件计算低质分解方法知识蒸馏方法 总体目录 核心代码实现 所有案例的配置文件 举例 初始化网络评价网络…

基于Vue和Element UI实现前后端分离和交互

目录 前言 一、Element UI简介 1.Element UI是什么 2.Element UI的特点 二、项目搭建 1.创建一个SPA项目 2.安装 Element-UI 3.导入组件 4.创建登陆注册界面 登录组件---Login.vue 注册组件---Register.vue 定义组件与路由的对应关系 效果演示&#xff1a; 三、前…

1.4.C++项目:仿muduo库实现并发服务器之buffer模块的设计

项目完整版在&#xff1a; 一、buffer模块&#xff1a; 缓冲区模块 Buffer模块是一个缓冲区模块&#xff0c;用于实现通信中用户态的接收缓冲区和发送缓冲区功能。 二、提供的功能 存储数据&#xff0c;取出数据 三、实现思想 1.实现换出去得有一块内存空间&#xff0c;采…

Redis与分布式-集群搭建

接上文 Redis与分布式-哨兵模式 1. 集群搭建 搭建简单的redis集群&#xff0c;创建6个配置&#xff0c;开启集群模式&#xff0c;将之前配置过的redis删除&#xff0c;重新复制6份 针对主节点redis 1&#xff0c;redis 2&#xff0c;redis 3都是以上修改内容&#xff0c;只是…

十、空闲任务及其钩子函数

1、空闲任务的介绍 (1)一个良好的程序&#xff0c;它的任务都是事件驱动的&#xff1a;平时大部分时间处于阻塞状态。 (2)有可能我们自己创建的所有任务都无法执行&#xff0c;但是调度器必须能找到一个可以运行的任务。所以&#xff0c;我们要提供空闲任务。 (3)在使用vTas…

格拉姆角场GAF将时序数据转换为图像并应用于凯斯西楚大学轴承故障诊断(Python代码,CNN模型)

1.运行效果&#xff1a; 格拉姆角场GAF将时序数据转换为图像并应用于故障诊断&#xff08;Python代码&#xff09;_哔哩哔哩_bilibili 环境库 只要tensorflow版本大于等于2.4.0即可运行 2.GAF的内容 GAF是一种用于时间序列数据可视化和特征提取的技术&#xff0c;通常用于…

Linux——补充点(进程切换及页表映射)

目录 补充点1&#xff1a;进程地址空间堆区管理 补充点2&#xff1a;Linux内核进程上下文切换 补充点3&#xff1a;页表映射 补充点4&#xff1a;两级页表 补充点1&#xff1a;进程地址空间堆区管理 Linux内核通过一个被称为进程描述符的task_struct结构体来管理进程&#…

keil调试的时候没问题,下载时候没反应

今天遇到这样一个问题。我下载商家的代码例程后单片机没反应&#xff0c;进入调试的时候一切正常。很奇怪&#xff0c;在网上找了教程问题解决&#xff0c;总结一下。 原因在于程序下载进去后没有按下复位键&#xff0c;导致还是之前的程序。我之前设置的是下载后自动复位运行…

【STL】用一棵红黑树封装map和set

⭐博客主页&#xff1a;️CS semi主页 ⭐欢迎关注&#xff1a;点赞收藏留言 ⭐系列专栏&#xff1a;C进阶 ⭐代码仓库&#xff1a;C进阶 家人们更新不易&#xff0c;你们的点赞和关注对我而言十分重要&#xff0c;友友们麻烦多多点赞&#xff0b;关注&#xff0c;你们的支持是我…

玩转gpgpu-sim 04记—— __cudaRegisterBinary() of gpgpu-sim 到底做了什么

官方文档&#xff1a; GPGPU-Sim 3.x Manual __cudaRegisterBinary(void*) 被执行到的代码逻辑如下&#xff1a; void** CUDARTAPI __cudaRegisterFatBinary( void *fatCubin ) { #if (CUDART_VERSION < 2010)printf("GPGPU-Sim PTX: ERROR ** this version of GPGPU…

小程序如何设置余额充值

在小程序中设置余额充值是一种非常有效的方式&#xff0c;可以帮助商家吸引更多的会员并提高用户的消费频率。下面将介绍如何在小程序中设置余额充值并使用。 第一步&#xff1a;创建充值方案 在小程序管理员后台->营销管理->余额充值页面&#xff0c;添加充值方案。可…

Spark性能监测+集群配置

spark-dashboard 参考链接 架构图 Spark官网中提供了一系列的接口可以查看任务运行时的各种指标 运行 卸载docker https://blog.csdn.net/wangerrong/article/details/126750198 sudo yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest…

Linux系统编程(七):线程同步

参考引用 UNIX 环境高级编程 (第3版)黑马程序员-Linux 系统编程 1. 同步概念 所谓同步&#xff0c;即同时起步、协调一致。不同的对象&#xff0c;对 “同步” 的理解方式略有不同 设备同步&#xff0c;是指在两个设备之间规定一个共同的时间参考数据库同步&#xff0c;是指让…

小白继续深入学习C++

第1节 指针的基本概念 1、变量的地址&#xff1a; 变量是内存地址的简称&#xff0c;在C中&#xff0c;每定义一个变量&#xff0c;系统就会给变量分配一块内存&#xff0c;内存是有地址的。 C用运算符&获取变量在内存中的起始地址。 语法&#xff1a; &变…

零基础Linux_9(进程)环境变量+进程地址空间+进程创建fork

目录 1. 环境变量 1.1 环境变量基本概念 1.2 环境变量PATH 1.3 环境变量HOME和SHELL 1.4 获取环境变量&#xff08;main函数参数&#xff09; 1.4.1 main函数第三个参数 1.4.2 设置普通变量和环境变量 1.4.3 main函数前两个参数 2. 进程地址空间 2.1 验证进程地址空…

PHP8的数据封装(数据隐藏)-PHP8知识详解

面向对象的特点之一就是封装性&#xff0c;也就是数据封装&#xff0c;也被称为数据隐藏。 php8通过限制访问权限来实现数据的封装性&#xff0c;这里用到了public、private、protected、static和final几个关键字。下面来介绍前3个。 1.、public&#xff08;公共成员&#xf…