最近折腾了一下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();
}
}
控制台输出:
启动线程用的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多线程之概述与三种创建方式主要内容,下一篇将介绍线程安全
与线程同步
。