java

一. Java多线程

1.什么是线程?

线程是操作系统能够进行调度的最小单位.一个进程包含多个线程,每个线程执行不同的任务.不同的进程使用不同的内存,同一个进程中的线程共享一片内存空间.

2.为什么需要线程?

一般我们启动一个程序就是启动一个进程,程序执行过程中由于程序控制范围之外的某些条件导致程序堵塞,程序此时只能中止;使用线程时,我们在该进程中创建多个线程,每个线程执行不同的任务,当由于某些外在条件导致某个线程堵塞时,其他线程仍然可以执行,不会导致程序中止.java中的线程机制是抢占式的,调度机会周期性的中断线程,将上下文切换到另外一个线程继续执行,使得每个线程都有时间去执行任务.

3.如何使用线程?

1)创建任务,实现runnable或者callable接口

class Cnt extends  Thread{
   
public void run(){
       
try {
            TimeUnit.
SECONDS.sleep(2);
        }
catch (InterruptedException e) {
            e.printStackTrace();
        };
        System.
out.println("Cnt thread is running!");
    }
}

class Cnt2 implements Runnable{
   
@Override
   
public void run() {
       
try {
            TimeUnit.
SECONDS.sleep(2);
        }
catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.
out.println("Cnt2 thread is running!");
    }
}

 

2)将任务添加到线程中执行;

一种方法是显示创建Thread,调用start()方法创建线程执行任务;

public class ThreadTest {
   
public static void main(String[] args){
        Cnt2 cnt2=
new Cnt2();
       
new Thread(cnt2).start();
        System.
out.println("Main Method!");
    }
}

 

一种方法是使用executor来创建CachedThreadPool/FixedThreadPool/SingleThreadPool来执行任务;

public class ThreadTest {
   
public static void main(String[] args){
        Cnt2 cnt2=
new Cnt2();
        ExecutorService exec= Executors.newCachedThreadPool();
        exec.execute(cnt2);
        exec.shutdown();
        System.
out.println("Main Method!");
    }
}

 

3)创建有返回结果的任务需要实现Callable<T>接口,返回Future<T>结果

import java.util.ArrayList;
import java.util.concurrent.*;

public class CallableTest {
   
public static void main(String[] args){
        ExecutorService exec= Executors.newCachedThreadPool();
        ArrayList<Future<String>> res=
new ArrayList<>();
       
for(int i=0;i<10;i++){
            res.add(exec.submit(
new TaskWithResult()));
        }
       
for(Future<String> fs:res){
           
try {
                System.
out.println(fs.get());
            }
catch (InterruptedException e) {
                e.printStackTrace();
            }
catch (ExecutionException e) {
                e.printStackTrace();
            }
finally {
               
if(!exec.isShutdown()){
                    exec.shutdown();
                }
            }
        }
    }
}


class TaskWithResult implements Callable<String> {
   
private static int id=0;
   
private final int cnt=id++;
   
@Override
   
public String call() throws Exception {

       
return "TaksWithResult-"+cnt;
    }
}

 

4.多线程互斥Mutext

保证多线程的互斥性有两种方法:synchronized内置锁或ReentrantLock显示锁;

为什么需要ReentrantLock?

1)RentrantLock使用时可以显示锁定和释放锁,在释放锁时可以有其他的控制;

2)Lock.tryLock()可以尝试获取锁,当获取不到锁时可以执行其他的操作,而不是一直等待;

 

代码如下:

public class Task implements Runnable{         
        private Lock lock=new ReentrantLock();         
        private int counter=0;         
        @Override 
        public void run() { 
                boolean captured=false; 
                captured=lock.tryLock(); 
                try{ 
                        if(captured){ 
                                counter++; 
                                System.out.println(counter+" "+captured); 
                        }else{ 
                                System.out.println("Not captured!"); 
                        } 
                }finally{ 
                        if(captured) lock.unlock(); 
                } 
        } 
} 

public class BasicThread{ 
        public static void main(String[] args){ 
                Task t=new Task(); 
                for(int i=0;i<10;i++){ 
                        new Thread(t).start(); 
                } 
        } 
} 
输出:
1 true 
Not captured! 
2 true 
3 true 
Not captured! 
4 true 
5 true 
6 true 
7 true 
8 true

可见,10个线程中有两个没有获取到锁,此时仍然会执行其后的语句

5.Volatile关键字

Volatile关键字用来修饰成员变量,作用是保证所修饰成员的可见性.可见性指在一个线程中修改的值,在其他线程中立即可以看到修改后的值.除了Volatile关键字,Synchronized和ReentrantLock也可以保证同步方法或同步块中内容的可见性.

private int i1;      public int geti1(){return i1;}

volatile private i1;  public int geti1{return i1;}

private int i1;      public synchronized int geti1{return i1;}

第一种方法中获取的是当前线程中的副本,不一定是最新值;

第二种方法中获取的是主存中的值,因为volatile修饰的变量不会存在副本;

第三种方法中获取的是当前线程中的副本,但是synchronized关键字保证了主存和副本的同步;

private int i1;      public void seti1(int v){ i1=v;}

volatile private i1;  public void seti1(int v){ i1=v;}

private int i1;      public void synchronized seti1(int v){ i1=v;}

第一种方法更新当前线程中的副本,其他线程不一定能立刻读取最新值;

第二种方法更新主存中的值,其他线程可以立马读取到;

第三种方法更新当前线程中的副本,但是synchronized关键字保证了将最新值更新到主存中,同时从主存读取最新值.

Volatile不能保证互斥,如下代码中,当有多个线程执行时,列表中元素的数量可能会超过100

public class VolatileTest implements Runnable{

    volatile private int count=0;

    ArrayList<Integer> list=new ArrayList<Integer>();

    @Override

    public void run() {

        if(count<1000){

            list.add(1);

            count++;

        }

    }

}

 

6.线程协作

1)wait() notify() notifyAll()

2)condition

7.什么是死锁?如何避免死锁?

死锁指多个线程因竞争资源导致互相等待的僵局,若无外力作用,这些线程都无法继续执行.例如A线程锁定资源1,等待资源2,B线程锁定资源2,等待资源1,此时二者造成死锁;

避免死锁的技术:

1)按照相同的顺序加锁;

2)线程加锁时加上一定的时限,超过时限放弃对锁的请求,并释放占有的锁;

3)死锁检测,每当一个线程获得锁时,会在线程和锁相关的数据结构中进行记录,当线程申请锁时,也会进行相应的记录.当某线程申请锁失败时,会遍历锁的关系图,查看该锁是否已经被某线程占用,同时该线程正在申请的锁被自己占用,如果有便发生了死锁.有时,可能锁的关系图比较复杂,涉及多个线程造成死锁.

当检测到死锁发生时,一个可行的方法是释放所有锁,回退,等待一段随机的时间后重试;一个更好的方法是给这些线程设置优先级(或者随机设置优先级),让一个或几个线程回退,其他的线程继续等待;

8.什么是活锁?如何避免?

活锁指任务的执行没有被阻塞,由于某些条件没有满足,导致一直重复尝试,失败,尝试,失败.两个线程发生某些条件的碰撞之后重新执行,再次尝试后依然发生碰撞,长此下去就会发生活锁.

解决活锁的方法:

当检测到冲突时,暂停随机的一段时间后重试,将减小再次冲突的可能性.

 

9.什么是竞态条件?

如果程序运行顺序的改变会影响最终结果,这就是一个竞态条件.

在多线程环境下经常会存在竞态条件,如

public class ObjFactory { 

    private Obj instance; 

    public Obj getInstance(){ 

        if(instance == null){ 

            instance = new Obj(); 

        } 

        return instance; 

    } 

}

如果线程A,B同时执行getInstance方法,可能出现线程A B两次创建instance的情况;

解决方法:采用同步,创建同步方法或同步块

10.线程池的应用场景?优点?java线程池有哪几种以及相应的应用场景?线程池如何调优?

1)应用场景

需要处理的任务数量多,且单个任务的处理时间短;

2)优点

当任务数量多时,频繁的创建和销毁线程将会耗费系统的资源,另外jvm中存在创建过多的活动线程也会消耗大量的内存.线程池中的线程执行任务结束后可以重用而不是销毁,减小线程创建和销毁的开销,另外线程池可以设置线程数量的阈值,线程数量超过阈值时,后续任务将一直等待.防止产生过多的线程;

3)Java中的线程使用Executors创建,下图展示了线程池的结构

  • newCachedThreadPool 根据需要创建新的线程,以前创建的空闲线程可以重用,如果没有可用的则重新创建.该线程池没有设置线程数量的上限,使用时一定要小心;
  • newFixedThreadPool 固定线程数量的线程池,当任务数量超过线程数量时,将在线程池队列中等待
  • newScheduledThreadPool 创建一个线程池,可以在给定的时间延迟后执行任务或者定期执行
  • newSingleThreadPool 使用单个worker线程来执行任务,多个任务按照提交的顺序依次执行

4)线程池调优

  • 不要将同步等待其他结果的任务排队.这些任务会长时间占用线程,导致无线程可用,长时间等待的任务需要设置最长等待时间,超时需要重新排队
  • 合理设置线程池的大小

11.原子类

在java.util.concurrent.atomic包中,有AtomicInteger,AtomicLong等类,使用原子类可以代替synchronized或者显示Lock锁

public class Counter1{

         private int counter;

         public synchronized int add(){

                   counter++;

}

}

使用原子类时如下

public class Counter2{

         private AtomicInteger counter=new AtomicInteger(0);

         public void add(){

         counter.incrementAndGet();

}

}

二者实现的效果是一样的,但是使用Atomic原子类的性能更好,原因是原子类内部通过JNI(Java native interface,java语言提供的与其他语言进行通讯的接口)的方式使用了硬件支持的CAS指令.

二. Java语法基础

1.Java语言三大特性

1)数据抽象:将想法从具体实例中抽象出来,根据功能创建类而不是细节;

2)继承:使得对象可以从基类获取对象和方法;

3)多态:使得多个类具有相同的接口,一个多态类型的操作可以应用到不同的类型的值上面;

2.容器

Java容器的作用是保存对象,实际上保存的是对象的引用,可以大致分为两类:

  1. Collection

一个独立元素的序列,这些序列服从一条或者多条准则.List按顺序存储元素,Set无序但是不能有重复的元素,Queue按照排队规则来确定元素的顺序;

  1. Map

一组成对的键值对元素,允许用键来查找值.

容器类的关系图如下

3) List

  • ArrayList底层基于数组实现,随机访问的速度快 ,但插入和删除速度慢,需要移动前后的元素,非同步实现;
  • Vector底层基于数组实现,同步实现,线程安全;
  • LinkedList底层基于链表实现,因此访问的速度慢,但是插入和删除的速度快,

4) Set

Set是一个集合,其中不能有重复元素.

  1. HashSet是无序的集合,内部使用HashMap存储内容,查询速度比较快;
  2. TreeSet是有序的集合,采用红-黑树结构;

5) Queue

Queue是先进先出的集合,有offer,peek,pool等方法;

  1. LinkedList是对Queue接口的实现,可以向上转型为Queue;
  2. PriorityQueue可以使队列中的元素按照优先级进行排序;

6) Map

Map用于存储键值对

  1. HashMap是基于哈希表的Map接口的实现,查询效率比较高,但是非同步的实现
  2. HashTable中方法基本与HashMap相同,只是增加了synchronized关键字进行了同步,虽然线程安全,但是效率比较低;
  3. TreeMap采用是有序的

java5以上中提供了ConcurrentHashmap的实现,用于并发场景;

7) Arrays

静态类,用于操作array,常用方法 List<T> Arrays.asList(T… element)

List<String> stooges=Arrays.asList(“Larry”,”Moe”,”Curly”);

8) Collections

静态类,用于操作Collection,常用方法 boolean Colllections.addAll(Collection<? Super T> c, T… elements)

Collections.addAll(flavors,”Rocket”,”Rain”)

三. JVM基础

动物目标检测数据集 一、基础信息 数据集名称:动物目标检测数据集 图片数量: - 训练集:9,134张图片 - 验证集:1,529张图片 - 测试集:1,519张图片 总计:12,182张图片 分类类别: Bear(熊)、Cat(猫)、Cattle(牛)、Chicken(鸡)、Deer(鹿)、Dog(狗)、Elephant(大象)、Horse(马)、Monkey(猴子)、Sheep(绵羊) 标注格式: YOLO格式,包含归一化坐标的边界框和数字编码类别标签,支持目标检测模型开发。 数据特性: 涵盖俯拍视角、地面视角等多角度动物影像,适用于复杂环境下的动物识别需求。 二、适用场景 农业智能监测: 支持畜牧管理系统开发,自动识别牲畜种类并统计数量,提升养殖场管理效率。 野生动物保护: 应用于自然保护区监控系统,实时检测特定动物物种,辅助生态研究和盗猎预警。 智能养殖设备: 为自动饲喂系统、健康监测设备等提供视觉识别能力,实现精准个体识别。 教育研究工具: 适用于动物行为学研究和计算机视觉教学,提供标准化的多物种检测数据集。 遥感图像分析: 支持航拍图像中的动物种群分布分析,适用于生态调查和栖息地研究。 三、数据集优势 多物种覆盖: 包含10类常见经济动物和野生动物,覆盖陆生哺乳动物与家禽类别,满足跨场景需求。 高密度标注: 支持单图多目标检测,部分样本包含重叠目标标注,模拟真实场景下的复杂检测需求。 数据平衡性: 经分层抽样保证各类别均衡分布,避免模型训练时的类别偏差问题。 工业级适用性: 标注数据兼容YOLO系列模型框架,支持快速迁移学习和生产环境部署。 场景多样性: 包含白天/夜间、近距离/远距离、单体/群体等多种拍摄条件,增强模型鲁棒性。
数据集介绍:农场与野生动物目标检测数据集 一、基础信息 数据集名称:农场与野生动物目标检测数据集 图片规模: - 训练集:13,154张图片 - 验证集:559张图片 - 测试集:92张图片 分类类别: - Cow(牛):农场核心牲畜,包含多种姿态和场景 - Deer(鹿):涵盖野外环境中的鹿类目标 - Sheep(羊):包含不同品种的绵羊和山羊 - Waterdeer(獐):稀有野生动物目标检测样本 标注格式: YOLO格式标准标注,含精确边界框坐标和类别标签 数据特征: 包含航拍、地面拍摄等多视角数据,适用于复杂环境下的目标检测任务 二、适用场景 智慧农业系统开发: 支持畜牧数量统计、牲畜行为监测等农业自动化管理应用 野生动物保护监测: 适用于自然保护区生物多样性监测系统的开发与优化 生态研究数据库构建: 为动物分布研究提供标准化视觉数据支撑 智能畜牧管理: 赋能养殖场自动化监控系统,实现牲畜健康状态追踪 多目标检测算法验证: 提供跨物种检测基准,支持算法鲁棒性测试 三、数据集优势 多场景覆盖能力: 整合农场环境与自然场景数据,包含光照变化、遮挡等真实场景 精确标注体系: - 经专业团队双重校验的YOLO格式标注 - 边界框精准匹配动物形态特征 数据多样性突出: - 包含静态、动态多种动物状态 - 涵盖个体与群体检测场景 任务适配性强: - 可直接应用于YOLO系列模型训练 - 支持从目标检测扩展到行为分析等衍生任务 生态研究价值: 特别包含獐等稀有物种样本,助力野生动物保护AI应用开发
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值