线程

基础

  1. getStackTrace()会返回函数栈,保存有调用类的名称,方法名,行号;返回的数据中,thread类的getstacktrace方法始终为最顶端,下标为0,之后为所调用的方法,最顶级的调用者在栈底,最新的在顶部,当方法结束后,栈中的信息也会清除
  2. 上方法中,0为getstacktrace方法,1位调用getstacktrace方法的类,2为更上一级
  3. 线程只可以被启动一次,重复启动时会报参数状态错误
  4. 使线程顺序执行得方法
  5. runnable方式开启的线程不能抛出异常;
    1. 因为run()方法是Runnable接口里面的方法,而Runnable接口在定义run()方法的时候没有抛出任何异常;
    2. 所以子类在重写run()方法的时候要小于或等于父类(Runnable)的run()方法的异常,所以父类没有抛出异常,子类不能抛出异常
  6. 多个线程访问同一个方法的局部变量时,不会出现线程安全问题,因为局部变量存储在栈中,属于线程私有的。
  7. 方法中仅使用局部变量时,是线程安全的,栈可以保证线程安全

ThreadLocal

  1. ThreadLocal本身并不真正存储线程的变量值,它只是一个工具,用来维护Thread内部的Map,帮助存和取
  2. 每一个线程维护本身的值,ThreadLocal为key,每个线程中,每个threadLocal对应值唯一
  3. Thread类中维护着一个ThreadLocalMap对象,实际的值存储在该map中
  4. 存值时,先获取到当前线程的map对象,以当前的ThreadLocal对象为key,进行值的存储,取值过程相同
  5. 在线程结束时可以调用ThreadLocal.clear()方法,这样会更快释放内存,不调用也可以,因为线程结束后也可以自动释放相关的ThreadLocal变量。
  6. 使用:
    1. 创建全局threadlocal变量,保证只有一个;(一般为静态,防止内存泄漏)
    2. 如果需要每个线程中存储多个值,可以创建多个threadlocal对象(每个threadlocal对应一个值的存储)
    3. 在不同的线程中,获取到全局threadlocal变量,执行set或者get方法(执行get方法前必须执行set,否则会报空指针异常)
    4. 在执行set方法时,会以ThreadLocal为key,值为传入的值(以此保证线程独立,但只能设置一个值)
  7. 可以在创建threadlocal时重载其中的initvalue方法,在调用get方法时,若未调用set,则会调用initvalue方法,以线程为key,initvalue方法的返回值为value;默认的initvalue方法的返回值为null;

ThreadLocal内存泄漏

  1. 其内部存储时,key ThreadLocal会被包装为弱引用,故当ThreadLocal为局部变量,或者被重新new了之后,ThreadLocal就会在gc时被回收,导致线程中的map的entry中保存有一个key为null的值,而key为null的entry无法被使用;
  2. 线程中的map生命周期和线程本身相同,若线程长时间存活,则会造成内存泄漏,map中某个无效的值一直无法被清理
  3. 在ThreadLocal的get()、set()、remove()都会清除线程map中key为null的entry
  4. 将ThreadLocal对象设置为静态,可以保证其不会在gc时被回收
  5. 单独使用线程时,则当线程被消耗时,其内部的值也会被回收,但在使用线程池时,就会出问题,所以在使用线程池时,线程结束前一定要清楚ThreadLocal值

特点

  1. countDownLatch

    1. CountDownLatch,一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
    2. countDownLatch是在java1.5被引入,跟它一起被引入的工具类还有CyclicBarrier、Semaphore、concurrentHashMap和BlockingQueue。
    3. countDownLatch这个类使一个线程等待其他线程各自执行完毕后再执行。
    4. 通过一个计数器来实现的,计数器的初始值是线程的数量。每当一个线程执行完毕后,计数器的值就-1,当计数器的值为0时,表示所有线程都执行完毕,然后在闭锁上等待的线程就可以恢复工作了。
    5. countDownLatch类中只提供了一个构造器:
    //参数count为计数值
    public CountDownLatch(int count) {  };  
    
    1. 类中有三个方法是最重要的:
    //调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行
    public void await() throws InterruptedException { };   
    //和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行
    public boolean await(long timeout, TimeUnit unit) throws InterruptedException { };  
    //将count值减1
    public void countDown() { };  
    

线程池

  1. 可以使用ThreadPoolExecutor 来详细配置线程池的信息,也可以使用executors中配置好的线程池,返回的类型为executorservice,实际构造的对象为threadpoolexecutor
  2. 线程池根据不同的类型,一般会将执行任务时生成的线程保存下来,初始时没有线程的,这些线程中执行的内容即run方法中的内容可以被后续的线程所替换,节省了创建线程和销毁线程的开销
  3. keepAliveTime 是指线程的空闲时间,当线程执行完后,并不销毁,等待后续的内容,一般针对corepoolsize和maxpoolsize之间的线程,也可以设置其针对所有线程
  4. .使用细节以及种类具体介绍
  5. 线程池的execute方法传入runnable对象,submit实现callable对象,也可以传入runnable获取返回结果

使用

  1. cpu的数量
    1. 最佳线程数目 = ((线程等待时间+线程CPU时间)/线程CPU时间 )* CPU数目因为很显然,线程等待时间所占比例越高,需要越多线程。线程CPU时间所占比例越高,需要越少线程。
    2. 一般io密集型为2n+1,cpu密集型n+1,2倍左右

Callable与Future的应用

  1. callable:
    1. run()方法返回值为void类型,所以在执行完任务之后无法返回任何结果
    2. Callable位于java.util.concurrent包下,它也是一个接口,在它里面也只声明了一个方法call():
    3. 是一个泛型接口,泛型为返回结果的类型
  2. future
    1. Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果。
    2. 可以通过get方法获取执行结果,该方法会阻塞直到任务返回结果。
    3. 同样是一个泛型接口
    4. 可以取消任务(详解
  3. FutureTask
    1. 集Runnable、Callable、Future于一身。
    2. 它首先实现了Runnable与Future接口,然后在构造函数中还要注入Callable对象(或者变形的Callable对象:Runnable + Result)
    3. FutureTask类既可以使用new Thread(Runnable r)放到一个新线程中跑,也可以使用ExecutorService.submit(Runnable r)放到线程池中
    4. 如果要有返回结果那么构造函数一定要注入一个Callable对象,或者注入一个Runnable对象加一个预先给定的结果

获取结果

  1. 当需要线程结果时,可以使用join
  2. 获取返回值可以通过实现call接口(泛型类型为返回值类型),然后将call接口的实现类传入futuretask(其继承了runnable和future,其泛型类型为call接口类型)类,然后可以通过将futuretask对象传入线程池或者构建线程,执行后,通过futuretask对象来获取返回值或取消线程的执行,其get方法会阻塞至线程结束
【使用教程】 一、环境配置 1、建议下载anaconda和pycharm 在anaconda中配置好环境,然后直接导入到pycharm中,在pycharm中运行项目 anaconda和pycharm安装及环境配置参考网上博客,有很多博主介绍 2、在anacodna中安装requirements.txt中的软件包 命令为:pip install -r requirements.txt 或者改成清华源后再执行以上命令,这样安装要快一些 软件包都安装成功后才算成功 3、安装好软件包后,把anaconda中对应的python导入到pycharm中即可(不难,参考网上博客) 二、环境配置好后,开始训练(也可以训练自己数据集) 1、数据集准备 需要准备yolo格式的目标检测数据集,如果不清楚yolo数据集格式,或者有其他数据训练需求,请看博主yolo格式各种数据集集合链接:https://blog.csdn.net/DeepLearning_/article/details/127276492 里面涵盖了上百种yolo数据集,且在不断更新,基本都是实际项目使用。来自于网上收集、实际场景采集制作等,自己使用labelimg标注工具标注的。数据集质量绝对有保证! 本项目所使用的数据集,见csdn该资源下载页面中的介绍栏,里面有对应的下载链接,下载后可直接使用。 2、数据准备好,开始修改配置文件 参考代码中data文件夹下的banana_ripe.yaml,可以自己新建一个不同名称的yaml文件 train:训练集的图片路径 val:验证集的图片路径 names: 0: very-ripe 类别1 1: immature 类别2 2: mid-ripe 类别3 格式按照banana_ripe.yaml照葫芦画瓢就行,不需要过多参考网上的 3、修改train_dual.py中的配置参数,开始训练模型 方式一: 修改点: a.--weights参数,填入'yolov9-s.pt',博主训练的是yolov9-s,根据自己需求可自定义 b.--cfg参数,填入 models/detect/yolov9-c.yaml c.--data参数,填入data/banana_ripe.yaml,可自定义自己的yaml路径 d.--hyp参数,填入hyp.scratch-high.yaml e.--epochs参数,填入100或者200都行,根据自己的数据集可改 f.--batch-size参数,根据自己的电脑性能(显存大小)自定义修改 g.--device参数,一张显卡的话,就填0。没显卡,使用cpu训练,就填cpu h.--close-mosaic参数,填入15 以上修改好,直接pycharm中运行train_dual.py开始训练 方式二: 命令行方式,在pycharm中的终端窗口输入如下命令,可根据自己情况修改参数 官方示例:python train_dual.py --workers 8 --device 0 --batch 16 --data data/coco.yaml --img 640 --cfg models/detect/yolov9-c.yaml --weights '' --name yolov9-c --hyp hyp.scratch-high.yaml --min-items 0 --epochs 500 --close-mosaic 15 训练完会在runs/train文件下生成对应的训练文件及模型,后续测试可以拿来用。 三、测试 1、训练完,测试 修改detect_dual.py中的参数 --weights,改成上面训练得到的best.pt对应的路径 --source,需要测试的数据图片存放的位置,代码中的test_imgs --conf-thres,置信度阈值,自定义修改 --iou-thres,iou阈值,自定义修改 其他默认即可 pycharm中运行detect_dual.py 在runs/detect文件夹下存放检测结果图片或者视频 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值