Java多线程之概述与三种创建方式

最近折腾了一下Java多线程相关的内容,来水几遍博客。。。

一、多线程之概述

1、什么是多线程?

线程这个概念前,我们先需要了解一下进程
在操作系统中,进程定义为,计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位。

进程与程序的区别

程序是指令、数据及其组织形式的描述,进程是程序的执行实体

我们都知道CPU执行速度非常快,但是一些IO操作、或者执行存在被某些事件打断的可能性。比如某个程序执行某处后等待输入,总不能让CPU停下来等吧。为了提高CPU的利用率,因此提出了进程概念,把CPU执行分成一个个非常短的时间片,轮流执行多个进程。当当前运行的进程A时间片到了或者某个事件打断了它,则换其他进程B继续执行,等进程A准备好了,下此再轮它来执行。

由于时间片非常短,再加上CPU执行速度非常快,这就给我一种错觉——多个进程在同时执行。实际上是微观上,同一时刻只能执行一个进程,但是宏观上是同时执行多个进程。(现在的多核CPU也实现了微观上的多进程)

有了进程为啥还有引入线程呢?原因是进程的切换比较耗资源,而一个进程又有将任务分小的需求,因此线程诞生了(当然也有子进程这个概念,由进程创建的进程)。

进程与线程的关系

一个进程可包含多个线程线程也称为轻量级进程

多线程就是在进程中创建多个线程,这多个线程来同时运行,用来提高CPU的运行效率。

2、线程的物种状态

线程从创建、运行到结束可分为五种状态:新建状态就绪状态运行状态阻塞状态死亡状态
新建状态:new操作符创建一个线程时,线程还没有开始运行
就绪状态:调用了线程的start方法
运行状态:执行run方法的过程
阻塞状态:进入睡眠、等待事件唤醒、等待时间片
死亡状态:线程执行完毕或者非正常死亡,资源被操作系统回收
在这里插入图片描述

3、多线程有啥应用场景?

多线程这个词,搞Java开发的应该都听说过,但是实际运用过的可能比较少。
前面听过扯多进程多线程可以提高CPU运行效率,那为啥很多人都没用过呢?
似乎多线程离我们很远,这不是自相矛盾吗?

迅雷同时下载多个片子使用过没?
电脑一边播放音乐,一遍编写word文件,也没用过?
多线程爬妹纸图也没用过?

多线程主要是为了提高完成任务的速度,因此在下载、批量操作等场景运用的比较多。

二、Java多线程创建方式

前面扯了这么久的理论,下面我们来做一点实际的,演示一下Java创建多线程的三种方式。

首先创建一个普通的Java项目即可。
在这里插入图片描述

方式一:继承Thread类,重写run方法

package cn.hestyle.demo;

/**
 * 继承Thread类,重写run方法
 */
class MyThread extends Thread{
    /**
     * 方法中放置需要执行的代码
     */
    @Override
    public void run() {
        for (int i = 0; i < 5; ++i) {
            System.out.println(this.getName() + " 输出 i = " + i);
        }
    }
}

/**
 * description: demo_01
 *
 * @author hestyle
 * @version 1.0
 * @className multi_thread_project_01->MultiThreadDemo01
 * @date 2020-02-09 15:35
 **/
public class MultiThreadDemo01 {
    public static void main(String[] args) {
        //创建两个线程
        MyThread myThread1 = new MyThread();
        MyThread myThread2 = new MyThread();
        //设置线程的名称,这样方便看输出结果
        myThread1.setName("线程一");
        myThread2.setName("线程二");
        //启动两个线程,注意:启动线程用的start方法,run方法直接运行
        myThread1.start();
        myThread2.start();
    }
}

控制台输出:
在这里插入图片描述
\color{red}注意: 启动线程用的start方法,run方法直接运行。直接的差别就是run执行的线程不会出现交叉执行(抢占CPU执行)。

方式二:实现Runnable接口,重写run方法

package cn.hestyle.demo;

/**
 * 实现Runnable接口,重写run方法
 */
class MyThreadTwo implements Runnable{
    /**
     * 方法中放置需要执行的代码
     */
    @Override
    public void run() {
        for (int i = 0; i < 5; ++i) {
            //Thread.currentThread()获取当前执行的线程
            System.out.println(Thread.currentThread().getName() + " 输出 i = " + i);
        }
    }
}

/**
 * description: demo_02
 *
 * @author hestyle
 * @version 1.0
 * @className multi_thread_project_01->MultiThreadDemo02
 * @date 2020-02-09 15:48
 **/
public class MultiThreadDemo02 {
    public static void main(String[] args) {
        MyThreadTwo threadTwo = new MyThreadTwo();
        //创建两个线程
        Thread thread1 = new Thread(threadTwo);
        Thread thread2 = new Thread(threadTwo);
        //设置线程的名称,这样方便看输出结果
        thread1.setName("线程一");
        thread2.setName("线程二");
        //启动两个线程,注意:启动线程用的start方法,run方法直接运行
        thread1.start();
        thread2.start();
    }
}

控制台输出信息:
在这里插入图片描述
其实Thread类也是Runnable接口的实现类。
实现Runnable接口并不就是线程,只有Thread才是线程!

方式三:使用匿名内部类

package cn.hestyle.demo;
/**
 * description: demo_02
 *
 * @author hestyle
 * @version 1.0
 * @className multi_thread_project_01->MultiThreadDemo02
 * @date 2020-02-09 15:48
 **/
public class MultiThreadDemo03 {
    public static void main(String[] args) {
        //以匿名内部类的形式创建两个线程
        Thread thread1 = new Thread(new Runnable() {
            /**
             * 方法中放置需要执行的代码
             */
            @Override
            public void run() {
                for (int i = 0; i < 5; ++i) {
                    //Thread.currentThread()获取当前执行的线程
                    System.out.println(Thread.currentThread().getName() + " 输出 i = " + i);
                }
            }
        });
        Thread thread2 = new Thread(new Runnable() {
            /**
             * 方法中放置需要执行的代码
             */
            @Override
            public void run() {
                for (int i = 0; i < 5; ++i) {
                    //Thread.currentThread()获取当前执行的线程
                    System.out.println(Thread.currentThread().getName() + " 输出 i = " + i);
                }
            }
        });
        //设置线程的名称,这样方便看输出结果
        thread1.setName("线程一");
        thread2.setName("线程二");
        //启动两个线程,注意:启动线程用的start方法,run方法直接运行
        thread1.start();
        thread2.start();
    }
}

控制台输出信息:
在这里插入图片描述
关于三种多线程的创建方式,实现Runnable接口使用的比较多,因为Java只支持类的单继承,第一种继承Thread类的方式不能再继承其它类。第三种匿名内部类的方式有时为了少写一些代码也会使用。

以上就是Java多线程之概述与三种创建方式主要内容,下一篇将介绍线程安全线程同步

发布了976 篇原创文章 · 获赞 230 · 访问量 20万+

猜你喜欢

转载自blog.csdn.net/qq_41855420/article/details/104235298