Java多线程基础

线程

线程和进程

进程是操作系统分配资源的最小单位,而线程是程序执行的最小单位,他们都是可以并发执行的。一个进程至少有一个线程,这些线程共享进程的资源空间。

线程简介

每个线程都有一个优先级,高优先级的线程比低优先级的线程先执行。优先级的取值范围是1到10的整数,默认是5。每个线程有可能被标记为一个守护线程。当一个线程创建另外一个新的线程对象,新的线程的优先级等于创建他的线程的优先级;如果新的线程对象是一个守护线程当且仅当创建他的线程是一个守护线程。

线程分类

Java线程分为守护线程(Daemon Thread)用户线程(User Thread)。守护线程和用户线程基本上是一样的,唯一的区别是如果用户线程全部退出运行了,不管有没有守护线程虚拟机都会退出。守护线程的作用是为其他的线程的运行提供服务,最典型的守护线程就是GC(垃圾回收期)。

创建线程

创建线程的方式

创建一个线程类有三种方式:

  • 继承Thread类
  • 实现Runnable接口
  • 实现Callable接口

Thread

Thread简介

Thread是创建线程最关键的一个类,这个词本身也代表线程,Thread类实现了Runnable接口。

代码示例

public class ThreadDemo extends Thread {
	public void run() {
		for (int i = 0; i < 60; i++) {
			System.out.println(getName() + ":" + i);
		}
	}
}
public class Demo{
    public static void main(String[] args) {
        ThreadDemo t1 = new ThreadDemo();
		ThreadDemo t2 = new ThreadDemo();
		t1.start();
		t2.start();
    }
}

Runnable

Runnable简介

Runnable是提供线程的接口,有一个抽象方法public abstract void run()。实现了这个接口的类必须实现它的run方法。

代码示例

public class Runnable implements Runnable{
    public void run() {
       public void run() {
           for (int i = 0; i < 60; i++) {
				System.out.println(Thread.currentThread().getName() + ":" + i);
           }
	   }
	}
}
public class Demo{
    public static void main(String[] args) {
        RunnableDemo run = new RunnableDemo();
        Thread t1 = new Thread(run);
        Thread t2 = new Thread(run);
        t1.start();
        t2.start();
    }
}

Callable和Future

Callable和Future简介

Thread和Runnable创建线程不能获取线程的返回值。从Java1.5开始,就提供了Callable和Future,通过他们可以在任务执行完毕之后得到任务执行结果。

  • Callable接口:可以返回一个结果或者抛出一个异常的一个任务,实现者定义一个没有参数的call方法。区别于Thread和Runnable的run方法,Calllable任务执行的方法是call。
  • Future接口:Future接口代表了异步计算的结果,提供了一些方法用于检查计算结果是否完成,获取计算结果等。FutureTask类提供了Future接口的实现,并且实现了Runnable接口。

代码案例

public class MyCallable implements Callable<Integer> {
    public Integer call() {
        int sum = 0;
        for (int i = 0; i <= 100; i++) {
            sum += i;
        }
        return new Integer(sum);
    }
}
public class Demo{
    public static void main(String[] args) {
        MyCallable callable = new MyCallable();
        FutureTask<Integer> result = new FutureTask<Integer>(callable);
        new Thread(result).start();
        try {
            Integer value = result.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

线程生命周期

线程状态

在Thread类中有一个内部枚举类State代表了线程的状态,一个线程从创建到销毁就是一个完整的生命周期。

public enum State {
    /**
     * 线程被创建,还没有开始运行
     */
    NEW,
    /**
     * 线程运行状态,运行状态的线程是正在被Java虚拟机执行,但是也可能正在等待操作系统的其他资源例如处理器
     */
    RUNNABLE,
    /**
     * 线程阻塞状态,等待监视器锁。处于阻塞状态线程是在等待监视器锁为了:进入同步代码块/方法或者被调用后重	  		 * 新进入同步代码/方法
     */
    BLOCKED,
    /**
     * 线程等待状态,一个线程处于等待状态由于调用了以下这几种方法:Object.wait;Thread.join;LockSupp
     * ort.park。处于等待的线程正在等待另一个线程执行一个特定的操作。
     */
    WAITING,
    /**
     * 线程超时等待状态,一个线程处于超时等待状态在一个特定的等待时间,由于调用了以下几个方法Thread.slee
     * p;Object.wait(long);Thread.join(long);LockSupport.parkNanos;LockSupport.parkUntil。
     */
    TIMED_WAITING,
    /**
     * 线程结束状态,线程已经执行完成了。
     */
    TERMINATED;
}

线程状态转换

线程状态转换图

线程从创建后就在几个状态中切换。下面是一个线程状态转换图,调用不同的方法就可以切换线程线程的状态。
在这里插入图片描述

运行状态&无限等待

调用Object.wait();Thread.join();LockSupport.park()方法可以让线程从运行状态进入到无限等待状态。

  • wait方法

    是属于Object类的,对象调用wait方法后会让当前持有对象锁的线程释放当前对象锁并进入等待队列。对象调用notify从等待队列随机选择一个线程唤醒去竞争对象锁,对象调用notifyall会唤醒等待队列中的所有线程去竞争对象锁。

    public class Demo {
        public static void main(String[] args) {
            Demo demo = new Demo();
            Thread t1 = new Thread(() -> {
                synchronized (demo) {
                    System.out.println("t1 start");
                    try {
                        demo.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("t1 end");
                }
            });
            Thread t2 = new Thread(() -> {
               synchronized (demo) {
                   System.out.println("t2 start");
                   System.out.println("t2 end");
                   demo.notify();
               }
            });
            t1.start();
            t2.start();
        }
    }
    
  • join方法

    是属于Thread类的,join方法是阻塞调用此方法的线程,当线程a调用线程b的b.join(long),线程a会阻塞直到线程b执行完成。

    public class Demo {
        public static void main(String[] args) throws Exception {
          	System.out.println("main start");
            Thread t1 = new Thread(() -> {
                System.out.println("t1 start");
                System.out.println("t1 end");
            });
            t1.start();
            t1.join();
            System.out.println("main end");
        }
    }
    
  • park方法

    是属于LockSupport类的,LockSupport是一个线程阻塞工具类,所有的方法都是静态方法,可以使用park方法来阻塞线程,使用unpart来唤醒线程。

    public class Demo {
        public static void main(String[] args) {
            System.out.println("main start");
            Thread t1 = new Thread(() -> {
                System.out.println("t1 start");
                LockSupport.park();
                System.out.println("t1 end");
            });
            t1.start();
            LockSupport.unpark(t1);
            System.out.println("main end");
        }
    }
    

运行状态&超时等待

调用Object.wait(long);Thread.join(long);LockSupport.park(long)方法可以让线程从运行状态进入到等待状态,直到到达等待时间或者主动唤醒。

  • wait(long)方法

    是属于Object类的,当对象调用wait(long)后会让当前持有对象锁的线程释放掉当前对象锁进入等待队列,直到到达等待时间或者对象调用notify或者notifyall从等待队列中唤醒线程,线程又重新开始竞争锁。

public class Demo {
    public static void main(String[] args) {
        Demo demo = new Demo();
        Thread t1 = new Thread(() -> {
            synchronized (demo) {
                for (int i = 0; i < 1000; i++) {
                    if (i == 500) {
                        try {
                            demo.wait(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println("------t1------: " + i);
                }
            }
        });
        Thread t2 = new Thread(() -> {
            synchronized (demo) {
                for (int i = 0; i < 1000; i++) {
                    System.out.println("------t2------: " + i);
                }
            }
        });
        t1.start();
        t2.start();
    }
}
  • join(long)方法

    是属于Thread类的,join(long)方法是阻塞调用此方法的线程,当线程a调用线程b的b.join(long),线程a会阻塞直到到达阻塞时间或者线程b执行完成。

public class Demo {
    public static void main(String[] args) throws Exception {
        System.out.println("main start");
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                System.out.println("----t1----: " + i);
            }
        });
        t1.start();
        t1.join(1);
        System.out.println("main end");
    }
}
  • parkUntil(long)和parkNanos(long)

    是属于LockSupport类的,LockSupport是一个线程阻塞工具类,所有的方法都是静态方法,可以使用parkUntil(long)和parkNanos(long)方法来阻塞线程。parkNanons是阻塞long时间,parkUntil是阻塞截止到long时间。

public class Demo {
    public static void main(String[] args) {
        System.out.println("main start");
        Thread t1 = new Thread(() -> {
            System.out.println("t1 start");
            LockSupport.parkNanos(3000000000L);
            System.out.println("t1 end");
        });
        t1.start();
        System.out.println("main end");
    }
}
public class Demo {
    public static void main(String[] args) throws Exception{
        System.out.println("main start");
        Thread t1 = new Thread(() -> {
            System.out.println("t1 start");
            String dateTimeStr = "2021-04-04 14:57:00";
            DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            LocalDateTime dateTime = LocalDateTime.parse(dateTimeStr, df);
            LockSupport.parkUntil(dateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli());
            System.out.println("t1 end");
        });
        t1.start();
        System.out.println("main end");
    }
}

无限等待&阻塞状态

对象调用wait方法后线程会进入无限等待状态,当对象调用notify或者notifyAll时,线程将从无限等待状态进入阻塞状态。

阻塞状态到运行状态

线程处于阻塞状态,如果获取到锁对象,就进入运行状态。

相关推荐
程序员的必经之路! 【限时优惠】 现在下单,还享四重好礼: 1、教学课件免费下载 2、课程案例代码免费下载 3、专属VIP学员群免费答疑 4、下单还送800元编程大礼包 【超实用课程内容】  根据《2019-2020年中国开发者调查报告》显示,超83%的开发者都在使用MySQL数据库。使用量大同时,掌握MySQL早已是运维、DBA的必备技能,甚至部分IT开发岗位也要求对数据库使用和原理有深入的了解和掌握。 学习编程,你可能会犹豫选择 C++ 还是 Java;入门数据科学,你可能会纠结于选择 Python 还是 R;但无论如何, MySQL 都是 IT 从业人员不可或缺的技能!   套餐中一共包含2门MySQL数据库必学的核心课程(共98课时)   课程1:《MySQL数据库从入门到实战应用》   课程2:《高性能MySQL实战课》   【哪些人适合学习这门课程?】  1)平时只接触了语言基础,并未学习任何数据库知识的人;  2)对MySQL掌握程度薄弱的人,课程可以让你更好发挥MySQL最佳性能; 3)想修炼更好的MySQL内功,工作中遇到高并发场景可以游刃有余; 4)被面试官打破沙锅问到底的问题问到怀疑人生的应聘者。 【课程主要讲哪些内容?】 课程一:《MySQL数据库从入门到实战应用》 主要从基础篇,SQL语言篇、MySQL进阶篇三个角度展开讲解,帮助大家更加高效的管理MySQL数据库。 课程二:《高性能MySQL实战课》主要从高可用篇、MySQL8.0新特性篇,性能优化篇,面试篇四个角度展开讲解,帮助大家发挥MySQL的最佳性能的优化方法,掌握如何处理海量业务数据和高并发请求 【你能收获到什么?】  1.基础再提高,针对MySQL核心知识点学透,用对; 2.能力再提高,日常工作中的代码换新貌,不怕问题; 3.面试再加分,巴不得面试官打破沙锅问到底,竞争力MAX。 【课程如何观看?】  1、登录CSDN学院 APP 在我的课程中进行学习; 2、移动端:CSDN 学院APP(注意不是CSDN APP哦)  本课程为录播课,课程永久有效观看时长 【资料开放】 课件、课程案例代码完全开放给你,你可以根据所学知识,自行修改、优化。  下载方式:电脑登录课程观看页面,点击右侧课件,可进行课程资料的打包下载。
<p> 课程演示环境:Windows10  </p> <p> 需要学习<span>Ubuntus</span>系统<span>YOLOv4-tiny</span>的同学请前往《<span>YOLOv4-tiny</span>目标检测实战:训练自己的数据集》 <span></span> </p> <p> <span> </span> </p> <p> <span style="color:#E53333;">YOLOv4-tiny</span><span style="color:#E53333;">来了!速度大幅提升!</span><span></span> </p> <p> <span> </span> </p> <p> <span>YOLOv4-tiny</span>在<span>COCO</span>上的性能可达到:<span>40.2% AP50, 371 FPS (GTX 1080 Ti)</span>。相较于<span>YOLOv3-tiny</span>,<span>AP</span>和<span>FPS</span>的性能有巨大提升。并且,<span>YOLOv4-tiny</span>的权重文件只有<span>23MB</span>,适合在移动端、嵌入式设备、边缘计算设备上部署。<span></span> </p> <p> <span> </span> </p> <p> 本课程将手把手地教大家使用<span>labelImg</span>标注和使用<span>YOLOv4-tiny</span>训练自己的数据集。课程实战分为两个项目:单目标检测(足球目标检测)和多目标检测(足球和梅西同时检测)。<span></span> </p> <p> <span> </span> </p> <p> 本课程的<span>YOLOv4-tiny</span>使用<span>AlexAB/darknet</span>,在<span>Windows10</span>系统上做项目演示。包括:<span>YOLOv4-tiny</span>的网络结构、安装<span>YOLOv4-tiny</span>、标注自己的数据集、整理自己的数据集、修改配置文件、训练自己的数据集、测试训练出的网络模型、性能统计<span>(mAP</span>计算<span>)</span>和先验框聚类分析。 <span> </span> </p> <p> <span> </span> </p> <p> 除本课程《<span>Windows</span>版<span>YOLOv4-tiny</span>目标检测实战:训练自己的数据集》外,本人推出了有关<span>YOLOv4</span>目标检测的系列课程。请持续关注该系列的其它视频课程,包括:<span></span> </p> <p> 《<span>Windows</span>版<span>YOLOv4</span>目标检测实战:训练自己的数据集》<span></span> </p> <p> 《<span>Windows</span>版<span>YOLOv4</span>目标检测实战:人脸口罩佩戴识别》<span></span> </p> <p> 《<span>Windows</span>版<span>YOLOv4</span>目标检测实战:中国交通标志识别》<span></span> </p> <p> 《<span>Windows</span>版<span>YOLOv4</span>目标检测:原理与源码解析》<span></span> </p> <p> <span> <img alt="" src="https://img-bss.csdnimg.cn/202007061503586145.jpg" /></span> </p> <p> <span><img alt="" src="https://img-bss.csdnimg.cn/202007061504169339.jpg" /><br /> </span> </p>
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页