java 线程馒头_java基础---线程

1.线程与进程

进程的概念

进程是表示资源分配的基本单位,又是调度运行的基本单位。例如,用户运行自己的程序,系统就创建一个进程,并为它分配资源,包括各种表格、内存空间、磁盘空间、I/O设备等。然后,把该进程放人进程的就绪队列。进程调度程序选中它,为它分配CPU以及其它有关资源,该进程才真正运行。

所以,进程是系统中的并发执行的单位。

线程的概念

线程是进程中执行运算的最小单位,亦即执行处理机调度的基本单位。如果把进程理解为在逻辑上操作系统所要完成的任务,那么线程表示完成该任务的许多可能的子任务之一。

2.线程的优势

(1)易于调度。

(2)提高并发性。通过线程可方便有效地实现并发。进程可创建多个线程来执行同一程序的不同部分或相同部分。

(3)开销少。创建线程比创建进程要快,所需开销很少。

(4)利于充分发挥多处理器的功能。通过创建多线程进程(即一个进程可具有两个或更多个线程),每个线程在一个处理器上运行,从而实现应用程序的并发性,使每个处理器都得到充分运行。

3.进程与线程的关系

(1)一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。

(2)资源分配给进程,同一进程的所有线程共享该进程的所有资源。

(3)处理机分给线程,即真正在处理机上运行的是线程。

(4)线程在执行过程中,需要协作同步。不同进程的线程间要利用消息通信的办法实现同步。

简单来说:

1)一个程序至少有一个进程,一个进程至少有一个线程.

2)进程在执行过程中拥有独立的资源,而多个线程共享进程中的资源

4.计算机中的进程

任务管理器可以列出当前运行的所有进程。在每个进程中有多个线程执行

5.线程的运行

多个线程同时抢占CPU的资源,谁先抢到谁先执行,没有先后顺序

6.线程的实现

线程实现的两种方式:继承Thread类、实现Runnable接口

7.线程实现方式一

第一种方式:继承Thread类

1)子类覆盖父类中的run方法,将线程运行的代码存放在run中。

2)建立子类对象的同时线程也被创建。

3)通过调用start方法开启线程。

注意:在Thread子类中,必须明确的覆写Thread类中的run()方法,此方法为线程的主体

举例:

public class ThreadTest extends Thread {

/**

* 线程实现方法一:继承Thread类

*/

private String name;

public ThreadTest(String name){

this.name=name;

}

@Override

public void run() {

for (int i = 0; i < 6; i++) {

System.out.println(name+"\t"+"i="+i);

}

}

public static void main(String[] args) {

//创建线程对象

ThreadTest t1=new ThreadTest("线程一");

ThreadTest t2=new ThreadTest("线程二");

//启动线程

t1.start();

// t1.run();

//启动线程

t2.start();

// t2.run();

}

}

8.线程的启动

如果要想正确的启动线程,是不能直接调用run()方法的,应该调用从Thread类中继承而来的start()方法,才可以启

动线程

9.Start()方法

public synchronized void start() {

if (threadStatus != 0)

throw new IllegalThreadStateException();

...

start0();

...

}

private native void start0();

从以上的代码中可以发现,在一个类中的start()方法调用时可能会抛出“IllegalThreadStateException”的异常,

一般在重复调用start()方法的时候会抛出这个异常。而且实际上此处真正调用的是start0()方法,此方法在声明处使用了native关键字声明,此关键字表示调用本机的操作系统函数,因为多线程的实现需要依靠底层操作系统支持。

10.线程的状态

要想实现多线程,必须在主线程中创建新的线程对象。任何线程一般具有五种状态,即创建、就绪、运行、阻塞、终止。

11.线程的生命周期

1)创建

在程序中,用构造方法创建了一个线程对象后,新的线程对象便会处于新建状态,此时,它已经有了相应的内存空间和其他资源,但还处于不可运行状态。新建一个线程对象可采用Thread类的构造方法来实现,例如:Thread thread = new Thread();

2)就绪

新建线程对象后,调用该线程的start()方法就可以启动线程,当启动线程,线程就处于就绪状态。此时,线程将进入线程队列排队,等到CPU服务,这表明它已经具备了运行条件。

3)运行

当就绪状态的线程被调用并获得处理器资源时,线程就进入了运行状态。此时,自动调用该线程的run()方法,run()方法定义了该线程的操作于功能

4)阻塞

一个正在执行的线程在某些特殊情况下,如被认为挂起或者需要执行耗时的输入/输出操作时,就会让出CPU并暂时中止自己的执行,进入堵塞状态。在可执行状态下,如果调用sleep(),suspend(),wait()等方法,线程都将进入堵塞状态。堵塞时,线程不能进入排队队列,只有当引起堵塞的原因被消除后,线程才可以进入就绪状态。

5)死亡|终止

线程调用stop()方法时或者run()方法执行结束后,即可处于死亡状态,处于死亡状态的线程不具有继续行为能力

12.线程实现方式二

第二种方式:

实现Runnable接口

1)子类覆盖接口中的run方法。

2)通过Thread类创建线程,并将实现了Runnable接口的子类对象作为参数传递给Thread类的构造函数。

3)Thread类对象调用start方法开启线程。

举例:

public class RunnableTest implements Runnable {

/**

* 线程实现方法二:实现Runnable接口

*/

private String name;

public RunnableTest(String name){

this.name=name;

}

@Override

public void run() {

for (int i = 0; i < 6; i++) {

System.out.println(name+"\t"+"i="+i);

}

}

public static void main(String[] args) {

//创建当前接口的对象

RunnableTest r1=new RunnableTest("线程一");

RunnableTest r2=new RunnableTest("线程二");

Thread t1=new Thread(r1);

Thread t2=new Thread(r2);

t1.start();

t2.start();

}

}

13.Thread类与Runnable接口的联系

Thread-->Runnable

MyThread-->Runnable  Thread-->MyThread

14.Thread类与Runnable接口的区别

Thread类和Runnable接口之间在使用上也是有所区别的,如果一个类继承Thread类,则不适合于多个线程共享资源,而实现了Runnable接口,则可以方便的实现资源的共享.

15.资源不共享的情况

举例:

/**

* 资源不共享的情况

* @author dell

*

*/

public class Test1 extends Thread{

private int ticket=5;

@Override

public void run() {

for (int i = 0; i <= 100; i++) {

if (ticket>0) {

System.out.println("票:"+ticket--);

}

}

}

public static void main(String[] args) {

//创建3个线程

Test1 t1=new Test1();

Test1 t2=new Test1();

Test1 t3=new Test1();

t1.start();

t2.start();

t3.start();

}

}

16.资源共享的情况

举例:

/**

* 资源共享

* @author dell

*

*/

public class Test2 implements Runnable{

private int ticket=5;

@Override

public void run() {

for(int i=1;i<=100;i++){

if(ticket>0){

System.out.println("票:"+ticket--);

}

}

}

public static void main(){

Test2 t=new Test2();

//创建三个线程

new Thread(t).start();

new Thread(t).start();

new Thread(t).start();

}

}

17.线程的方法

Thread类中的主要方法如下

方法                                        描述

public static Thread currentThread()        返回当前的线程

public final String getName()               返回线程名称

public final void setPriority(int priority) 设置线程优先级

public void start()                         开始执行线程

public static void sleep(long m)            使用目前的线程休眠m秒(释放执行权和不释放锁)

public final void yield()                   暂停目前的线程,运行其他线程

public void run()                           执行线程

静态方法可以由类名直接调用

举例:

public class SleepTest extends Thread{

@Override

public void run() {

// TODO Auto-generated method stub

for (int i = 0; i <= 3; i++) {

System.out.println("i="+i);

try {

//当前线程休眠2秒钟

Thread.currentThread().sleep(3000);

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

public static void main(String[] args) {

new SleepTest().start();

}

}

18.Join()

举例

Join代码实现打酱油情景-mother

public class MotherThread implements Runnable

{

public void run()

{

System.out.println("妈妈准备煮饭");

System.out.println("妈妈发现米酒用完了");

System.out.println("妈妈叫儿子去买米酒");

Thread son = new Thread(new SonThread()); //儿子线程创建

son.start(); //启动儿子线程

System.out.println("妈妈等待儿子把米酒买回来");

try {

son.join(); //儿子线程加入,并获得资源开始运行

}

catch (Exception ie)

{

System.err.println("发生异常!");

System.err.println("妈妈中断煮饭");

System.exit(1);

}

System.out.println(“妈妈开始煮饭”); //妈妈线程继续运行

System.out.println("妈妈把饭煮好了");

}

}

Join代码实现打酱油情景-son

public class SonThread implements Runnable

{

public void run() //儿子线程的运行主体

{

System.out.println("儿子出门去买米酒");

System.out.println("儿子买东西来回需要5分钟");

try {

for (int i=1; i<=5; i++)

{

Thread.sleep(2000);

System.out.print(i+"分钟");

}

}

catch (InterruptedException ie)

{

System.err.println("儿子发生意外");

}

System.out.println("\n儿子买米酒回来了");

}

}

Join代码实现打酱油情景-执行

public class Cooking

{

public static void main(String argv[])

{

Thread mother = new Thread(new MotherThread());

mother.start(); //只启动妈妈线程

}

}

19.setPriority()设置优先级

每个线程执行时都具有一定的优先级,优先级高的线程获得较多的执行机会,而优先级低的线程则获得较少的执行机会

public static final int MIN_PRIORITY 最低优先级1

public static final int NORM_PRIORITY 中等优先级,线程默认的优先级5

public static final int MAX_PRIORITY 最高优先级10

举例:

public class ThreadTest extends Thread {

private String name;

public ThreadTest(String name){

this.name=name;

}

@Override

public void run() {

for (int i = 0; i < 6; i++) {

System.out.println(name+"\t"+"i="+i);

}

}

public static void main(String[] args) {

//创建线程对象

ThreadTest t1=new ThreadTest("线程一");

ThreadTest t2=new ThreadTest("线程二");

//设置优先级

t2.setPriority(10);

//启动线程

t1.start();

//启动线程

t2.start();

}

}

20.sleep() 线程的休眠

在程序中允许一个线程进行暂时的休眠,直接使用Thread.sleep()方法即可

21.yield()线程的礼让

在线程操作中,也可以使用yield()方法将一个线程的操作暂时让给其他线程执行。

举例:

class MyThread implements Runnable { // 实现Runnable接口

public void run() { // 覆写run()方法

for (int i = 0; i < 5; i++) { // 不断输出

System.out.

println(Thread.currentThread().getName()

+ "运行--> " + i); //输出线程名称

if (i == 3) {

System.out.print("线程礼让:");

Thread.currentThread().yield() ; // 线程礼让

}

}

}

}

public class ThreadYieldDemo {

public static void main(String args[]) {

MyThread my = new MyThread() ; // 实例化MyThread对象

Thread t1 = new Thread(my, "线程A") ; //定义线程对象

Thread t2 = new Thread(my, "线程B"); //定义线程对象

t1.start() ; // 启动多线程

t2.start() ; // 启动多线程

}

}

22.线程的结束

线程会以以下三种方式之一结束:

1)线程到达其run()方法的末尾;

2)线程抛出一个未捕获到的Exception或Error;

3)调用stop方法

23.Object类对线程的支持

方法                             描述

public final void wait()            线程等待

public final void wait(long timeout)线程等待,并指定等待时间,以毫秒为单位(释放执行权和锁)

Public void notify()                唤醒第一个等待的线程

Public void notifyAll()             唤醒全部等待的线程

24.同步

A正在用这个资源

B也想用,但需要等待A将资源释放才可以使用

C也想用这个资源,也在等待A用完以后才可以使用

25.异步

A大家一起用

B好的好的,一起一起

C就是就是,资源共享

三个部分是融合在一起的

26.同步的特点

消耗资源,但是安全

1)同步的前提:

同步需要两个或者两个以上的线程。

多个线程使用的是同一资源。

未满足这两个条件,不能称其为同步

2)同步的弊端:

当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率。

27.线程的同步

同步是指在同一时间段内只能运行一个线程

同步可以解决线程中的安全问题

实现线程同步有俩种方法:同步代码块、同步方法

举例:

/**

* 线程同步案例

* */

public class TestSync implements Runnable {

Timer timer=new Timer();

public static void main(String[] args) {

TestSync test=new TestSync();

Thread t1=new Thread(test);

Thread t2=new Thread(test);

t1.setName("t1");

t2.setName("t2");

t1.start();

t2.start();

}

public void run(){

timer.add(Thread.currentThread().getName());

}

}

class Timer{

private static int num=0;

//同步synchronized

public synchronized void add(String name){

synchronized (this) {

num++;

try {

Thread.sleep(1);

} catch (InterruptedException e) {

}

System.out.println(name+",你是第"+num+"个使用timer的线程");

}

}

}

28.死锁

同步的过程中会出现死锁

举例

//死锁

public class TestDeadLock implements Runnable {

public int flag=1;//表示角色,儿子或者爸爸

static Object o1=new Object(),o2=new Object();//表示成绩单或者玩具

@Override

public void run() {

//输出状态

System.out.println("flag="+flag);

if (flag==1) {

synchronized (o1) {

try {

Thread.sleep(500);

} catch (InterruptedException e) {

e.printStackTrace();

}

synchronized (o2) {

System.out.println("1");

}

}

}

if (flag==0) {

synchronized (o2) {

try {

Thread.sleep(500);

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

synchronized(o1) {

System.out.println("0");

}

}

}

}

public static void main(String[] args) {

TestDeadLock td1=new TestDeadLock();

TestDeadLock td2=new TestDeadLock();

td1.flag=1;

td2.flag=0;

Thread t1=new Thread(td1);

Thread t2=new Thread(td2);

t1.start();

t2.start();

}

}

29.线程通信-生产者和消费者问题

生成者、店员、消费者

1-生产者生产产品

2-生产者通知消费者可以取产品

3-消费者取走产品

4-消费者通知生产者可继续生产

举例:

/**生产者消费者问题,涉及到几个类

* 第一,这个问题本身就是一个类,即主类

* 第二,既然是生产者、消费者,那么生产者类和消费者类就是必须的

* 第三,生产什么,消费什么,所以物品类是必须的,这里是馒头类

* 第四,既然是线程,那么就不是一对一的,也就是说不是生产一个消费一个,既然这样,多生产的往哪里放,

*      现实中就是筐了,在计算机中也就是数据结构,筐在数据结构中最形象的就是栈了,因此还要一个栈类

*/

public class ProduceConsume {

public static void main(String[] args) {

SyncStack ss = new SyncStack();//建造一个装馒头的框

Producer p = new Producer(ss);//新建一个生产者,使之持有框

Consume c = new Consume(ss);//新建一个消费者,使之持有同一个框

Thread tp = new Thread(p);//新建一个生产者线程

Thread tc = new Thread(c);//新建一个消费者线程

tp.start();//启动生产者线程

tc.start();//启动消费者线程

}

}

//馒头类

class SteamBread{

int id;//馒头编号

SteamBread(int id){

this.id = id;

}

public String toString(){

return "steamBread:"+id;

}

}

//装馒头的框,栈结构

class SyncStack{

int index = 0;

SteamBread[] stb = new SteamBread[6];//构造馒头数组,相当于馒头筐,容量是6

//放入框中,相当于入栈

public synchronized void push(SteamBread sb){

while(index==stb.length){//筐满了,即栈满,

try {

this.wait();//让当前线程等待

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

this.notify();//唤醒在此对象监视器上等待的单个线程,即消费者线程

stb[index] = sb;

this.index++;

}

//从框中拿出,相当于出栈

public synchronized SteamBread pop(){

while(index==0){//筐空了,即栈空

try {

this.wait();

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

this.notify();

this.index--;//push第n个之后,this.index++,使栈顶为n+1,故return之前要减一

return stb[index];

}

}

//生产者类,实现了Runnable接口,以便于构造生产者线程

class Producer implements Runnable{

SyncStack ss = null;

Producer(SyncStack ss){

this.ss = ss;

}

@Override

public void run() {

// 开始生产馒头

for(int i=0;i<20;i++){

SteamBread stb = new SteamBread(i);

ss.push(stb);

System.out.println("生产了"+stb);

try {

Thread.sleep(10);//每生产一个馒头,睡觉10毫秒

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

//消费者类,实现了Runnable接口,以便于构造消费者线程

class Consume implements Runnable{

SyncStack ss = null;

public Consume(SyncStack ss) {

super();

this.ss = ss;

}

@Override

public void run() {

// TODO Auto-generated method stub

for(int i=0;i<20;i++){//开始消费馒头

SteamBread stb = ss.pop();

System.out.println("消费了"+stb);

try {

Thread.sleep(100);//每消费一个馒头,睡觉100毫秒。即生产多个,消费一个

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1 目标检测的定义 目标检测(Object Detection)的任务是找出图像中所有感兴趣的目标(物体),确定它们的类别和位置,是计算机视觉领域的核心问题之一。由于各类物体有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具有挑战性的问题。 目标检测任务可分为两个关键的子任务,目标定位和目标分类。首先检测图像中目标的位置(目标定位),然后给出每个目标的具体类别(目标分类)。输出结果是一个边界框(称为Bounding-box,一般形式为(x1,y1,x2,y2),表示框的左上角坐标和右下角坐标),一个置信度分数(Confidence Score),表示边界框中是否包含检测对象的概率和各个类别的概率(首先得到类别概率,经过Softmax可得到类别标签)。 1.1 Two stage方法 目前主流的基于深度学习的目标检测算法主要分为两类:Two stage和One stage。Two stage方法将目标检测过程分为两个阶段。第一个阶段是 Region Proposal 生成阶段,主要用于生成潜在的目标候选框(Bounding-box proposals)。这个阶段通常使用卷积神经网络(CNN)从输入图像中提取特征,然后通过一些技巧(如选择性搜索)来生成候选框。第二个阶段是分类和位置精修阶段,将第一个阶段生成的候选框输入到另一个 CNN 中进行分类,并根据分类结果对候选框的位置进行微调。Two stage 方法的优点是准确度较高,缺点是速度相对较慢。 常见Tow stage目标检测算法有:R-CNN系列、SPPNet等。 1.2 One stage方法 One stage方法直接利用模型提取特征值,并利用这些特征值进行目标的分类和定位,不需要生成Region Proposal。这种方法的优点是速度快,因为省略了Region Proposal生成的过程。One stage方法的缺点是准确度相对较低,因为它没有对潜在的目标进行预先筛选。 常见的One stage目标检测算法有:YOLO系列、SSD系列和RetinaNet等。 2 常见名词解释 2.1 NMS(Non-Maximum Suppression) 目标检测模型一般会给出目标的多个预测边界框,对成百上千的预测边界框都进行调整肯定是不可行的,需要对这些结果先进行一个大体的挑选。NMS称为非极大值抑制,作用是从众多预测边界框中挑选出最具代表性的结果,这样可以加快算法效率,其主要流程如下: 设定一个置信度分数阈值,将置信度分数小于阈值的直接过滤掉 将剩下框的置信度分数从大到小排序,选中值最大的框 遍历其余的框,如果和当前框的重叠面积(IOU)大于设定的阈值(一般为0.7),就将框删除(超过设定阈值,认为两个框的里面的物体属于同一个类别) 从未处理的框中继续选一个置信度分数最大的,重复上述过程,直至所有框处理完毕 2.2 IoU(Intersection over Union) 定义了两个边界框的重叠度,当预测边界框和真实边界框差异很小时,或重叠度很大时,表示模型产生的预测边界框很准确。边界框A、B的IOU计算公式为: 2.3 mAP(mean Average Precision) mAP即均值平均精度,是评估目标检测模型效果的最重要指标,这个值介于0到1之间,且越大越好。mAP是AP(Average Precision)的平均值,那么首先需要了解AP的概念。想要了解AP的概念,还要首先了解目标检测中Precision和Recall的概念。 首先我们设置置信度阈值(Confidence Threshold)和IoU阈值(一般设置为0.5,也会衡量0.75以及0.9的mAP值): 当一个预测边界框被认为是True Positive(TP)时,需要同时满足下面三个条件: Confidence Score > Confidence Threshold 预测类别匹配真实值(Ground truth)的类别 预测边界框的IoU大于设定的IoU阈值 不满足条件2或条件3,则认为是False Positive(FP)。当对应同一个真值有多个预测结果时,只有最高置信度分数的预测结果被认为是True Positive,其余被认为是False Positive。 Precision和Recall的概念如下图所示: Precision表示TP与预测边界框数量的比值 Recall表示TP与真实边界框数量的比值 改变不同的置信度阈值,可以获得多组Precision和Recall,Recall放X轴,Precision放Y轴,可以画出一个Precision-Recall曲线,简称P-R
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值