美文网首页程序员
一、快速认识多线程

一、快速认识多线程

作者: _Colbert | 来源:发表于2020-10-01 21:10 被阅读0次

1.1 线程的介绍

​ 对于计算机来说,一个任务就是一个进程,而一个进程最少包含一个线程。每启动一个JVM虚拟机,就会启动一个线程。例如:在使用360安全卫士的时候,可以同时进行病毒查杀和垃圾清理,这就开启了两个不同的线程。

1.2 创建一个线程:

  1. 创建一个线程,重写run()方法。
  2. 启动线程,调用start()方法。
public static void main(String[] args) throws InterruptedException {

        new Thread(){
            @Override
            public void run() {
                for (int i = 0; i <100 ; i++) {
                    System.out.println("听歌");
                    try {
                        
                        // 加上sleep让两个线程交替更明显
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

            }
        }.start();
        for (int i = 0; i < 100; i++) {
            System.out.println("看视频");
            Thread.sleep(100);
        }

    }

听歌
看视频
听歌
看视频
听歌
看视频
听歌
......

1.3 线程的生命周期

​ 线程的生命周期大概可以分为五个部分:

image.png

1.3.1 NEW(新建)

​ 用new关键字创建一个线程而不调用start方法启动,这时候为Thread对象的NEW状态。在没有调用start方法之前,线程是不存在的,所以一般不说是线程的NEW状态。

1.3.2 RUNNABLE(可运行)

​ 调用start方法后,线程才被创建,此时该线程并不一定会立即执行,该线程必须等到CPU的调度才会执行,而等待的这个状态就是RUNNABLE状态。

1.3.3 RUNNING(运行)

​ 当CPU选中该线程时(通过轮询或其他方式),那么此时它才能真正执行自己的代码,此时进入RUNNING状态。

RUNNING转换为其他状态:

  • stop( ) ——> TERMINATED。
  • sleep( )、wait( ) ——> BLOCKED。
  • 进行某个阻塞的IO操作 ——> BLOCKED。
  • 获取某个锁资源,加入到阻塞队列 ——> BLOCKED。
  • CPU轮询放弃执行该线程 ——> RUNNABLE。
  • 线程主动调用yield()方法 ——> RUNNABLE。

1.3.4 BLOCKED(阻塞)

​ 1.3.3中的介绍了进入BLOCKED状态的情况。

BLOCKED进入其他状态:

  • stop()、意外死亡 ——> TERMINATED。
  • 阻塞结束 ——> RUNNABLE。
  • 休眠(sleep)结束 ——> RUNNABLE。
  • wait中,其他线程调用notify()/ notifyall ( )唤醒 ——> RUNNABLE。
  • 获得的了锁资源 ——> RUNNABLE。
  • 阻塞过程被打断(如:其他线程调用interrupt()),——> RUNNABLE。

1.3.5 TERMINATED/DEAD(死亡)

​ TERMINATED是线程的最终状态,在该状态中不会再切换到其他状态,该状态意味着线程的生命周期结束。

进入TERMINATED状态有以下几种情况:

  • 线程正常结束,结束生命周期。
  • 线程运行出错,意外结束。
  • JVM Crash,导致所有线程结束。

1.4 模板设计模式

从start()方法可以学习模板设计模式:

print类似Thread的start方法,wrapPrint类似run方法。

public class TemplateDemo {

    /**
     * 父类搭建好流程模板
     * @param message
     */
    public final void print(String message){
        System.out.println("########");
        warpPrint(message);
        System.out.println("########");
    }

    /**
     * 空的方法,让不同的子类去实现不同的逻辑
     * @param message
     */
    protected void warpPrint (String message){


    }

    public static void main(String[] args) {

        new TemplateDemo(){
            @Override
            protected void warpPrint(String message) {
                System.out.println(message);
            }
        }.print("hello");

        new TemplateDemo(){
            @Override
            protected void warpPrint(String message) {
                System.out.println(message);
            }
        }.print("java");
    }


########
hello
########
########
java
########

1.5 Runnable接口以及策略模式

很多文章说创建线程有两种方式:一种是继承Thread,另一种是实现Runnable接口。这种说法是不严谨的,只有Thread才是代表线程,而线程里面的逻辑可以由这两种方法来实现。

public class TicketWindowRunnable implements Runnable {
    
    // 没用static修饰,无论用static,还是采用这种Runnable的方式,都有线程安全问题。
    private int index = 1;
   
    private final static int MAX = 50;
    @Override
    public void run() {
        while (index < MAX) {
            System.out.println(Thread.currentThread() + "的号码是" + (index++));
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class TestTicketWindow {
    public static void main(String[] args) {
        final TicketWindowRunnable task = new TicketWindowRunnable();
        new Thread(task, "一号窗口").start();
        new Thread(task, "二号窗口").start();
        new Thread(task, "三号窗口").start();
        new Thread(task, "四号窗口").start();
    }
}
Thread[一号窗口,5,main]的号码是1
Thread[二号窗口,5,main]的号码是2
Thread[四号窗口,5,main]的号码是3
Thread[三号窗口,5,main]的号码是4
Thread[三号窗口,5,main]的号码是5
Thread[四号窗口,5,main]的号码是6
Thread[二号窗口,5,main]的号码是7
Thread[一号窗口,5,main]的号码是8

note Thread.sleep()更优雅的写法

  1. Thread.sleep(10)
  2. Thread.sleep(10*1000);
  3. Thread.sleep(10601000);
  1. TimeUnit.MILLISECONDS.sleep(10);
  2. TimeUnit.SECONDS.sleep(10);
  3. TimeUnit.MINUTES.sleep(10);

相关文章

  • 一、快速认识多线程

    1.1 线程的介绍 ​ 对于计算机来说,一个任务就是一个进程,而一个进程最少包含一个线程。每启动一个JVM虚拟...

  • GCD的使用,同步和异步,串行和并行

    多线程并发(同时)执行,其实就是CPU快速地在多线程之间的快速调度,就会造成多线程并发执行的假象;多线程下,不要相...

  • go实现快速排序

    第一,单线程实现快速排序 第二,多线程实现快速排序

  • C语言多线程基础入门

    多线程的优势 线程创建更加快速 线程间切换更加快速 线程容易终止 线程间通讯更快速 C语言的多线程可以通过gcc编...

  • 蚂蚁Java互联网架构师第1期高端

    教程目录 ├─0001-多线程快速入门.zip ├─0002-多线程之间实现同步.zip ├─0003--多线程之...

  • python 多线程,多进程的快速实现 concurrent,

    python 多线程,多进程的快速实现 concurrent, joblib, multiprocessing, ...

  • JAVA-多线程 (一) 认识多线程

    引导 要想了解多线程,必须先了解线程,而要想了解线程,必须先了解进程,因为线程是依赖于进程而存在。 什么是进程? ...

  • Python “多线程”及其适用范围和缺点

    Python多线程的一些理解: 1.多线程采用的是分时复用技术,即不存在真正的多线程,cpu做的事是快速地切换线程...

  • iOS多线程随笔

    1. 多线程的并发控制 1.1 在CGD中快速实现多线程的并发控制 NSOperationQueue来处理并发控制...

  • 作业2

    013-每特教育&蚂蚁课堂-第七期-从零开始学习多线程技术-多线程技术快速入门 什么是多线程 进程与线程的区别 多...

网友评论

    本文标题:一、快速认识多线程

    本文链接:https://www.haomeiwen.com/subject/ojrvuktx.html