首页 > 编程语言 >Java 多线程知识的简单总结

Java 多线程知识的简单总结

时间:2022-10-10 22:00:57浏览次数:84  
标签:总结 Java Thread 中断 线程 sleep 多线程 方法 public

Java 提供了多线程编程的内置支持,让我们可以轻松开发多线程应用。

Java 中我们最为熟悉的线程就是 main 线程——主线程。

一个进程可以并发多个线程,每条线程并行执行不同的任务。线程是进程的基本单位,是一个单一顺序的控制流,一个进程一直运行,直到所有的“非守护线程”都结束运行后才能结束。Java 中常见的守护线程有:垃圾回收线程、

这里简要述说以下并发和并行的区别。

并发:同一时间段内有多个任务在运行

并行:同一时间点上有多个任务同时在运行

多线程可以帮助我们高效地执行任务,合理利用 CPU 资源,充分地发挥多核 CPU 的性能。但是多线程也并不总是能够让程序高效运行的,多线程切换带来的开销、线程死锁、线程异常等等问题,都会使得多线程开发较单线程开发更麻烦。因此,有必要学习 Java 多线程的相关知识,从而提高开发效率。

1 创建多线程

根据官方文档 ​​Thread (Java Platform SE 8 ) (oracle.com)​​ 中 ​​java.lang.Thread​​ 的说明,可以看到线程的创建方式主要有两种:

There are two ways to create a new thread of execution. One is to declare a class to be a subclass of Thread. This subclass should override the run method of class Thread. An instance of the subclass can then be allocated and started.

The other way to create a thread is to declare a class that implements the Runnable interface. That class then implements the run method. An instance of the class can then be allocated, passed as an argument when creating Thread, and started.

可以看到,有两种创建线程的方式:

  • 声明一个类继承​Thread​​ 类,这个子类需要重写​​run​​ 方法,随后创建这个子类的实例,这个实例就可以创建并启动一个线程执行任务;
  • 声明一个类实现接口​​Runnable​​ 并实现​​run​​ 方法。这个类的实例作为参数分配给一个​​Thread​​ 实例,随后使用​​Thread​​ 实例创建并启动线程即可

除此之外的创建线程的方法,诸如使用 ​​Callable​​ 和 ​​FutureTask​​、线程池等等,无非是在此基础上的扩展,查看源码可以看到 ​​FutureTask​​ 也实现了 ​​Runnable​​ 接口。

使用继承 Thread 类的方法创建线程的代码:

/**
* 使用继承 Thread 类的方法创建线程
*/
public class CreateOne {
public static void main(String[] args) {
Thread t = new MySubThread();
t.start();
}
}

class MySubThread extends Thread {
@Override
public void run() {
// currentThread() 是 Thread 的静态方法,可以获取正在执行当前代码的线程实例
System.out.println(Thread.currentThread().getName() + "执行任务");
}
}

// ================================== 运行结果
Thread-0执行任务

使用实现 Runnable 接口的方法创建线程的代码:

/**
* 使用实现 Runnable 接口的方法创建线程
*/
public class CreateTwo {
public static void main(String[] args) {
RunnableImpl r = new RunnableImpl();
Thread t = new Thread(r);
t.start();
}
}

class RunnableImpl implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "执行任务");
}
}

// ================================== 运行结果
Thread-0执行任务

1.1 孰优孰劣

创建线程虽然有两种方法,但是在实际开发中,使用实现接口 ​​Runnable​​ 的方法更好,原因如下:

  1. 查看​​Thread​​ 的​​run​​ 方法,可以看到:
// Thread 实例的成员变量 target 是一个 Runnable 实例,可以通过 Thread 的构造方法传入
private Runnable target;

// 如果有传入 Runnable 实例,那么就执行它的 run 方法
// 如果重写,就完全执行我们自己的逻辑
public void run() {
if (target != null) {
target.run();
}
}
  1. 查看上面的源码,我们可以知道,Thread 类并不是定义执行任务的主体,而是​​Runnable​​ 定义执行任务内容,​​Thread​​ 调用执行,从而实现线程与任务的解耦。
  2. 由于线程与任务解耦,我们可以复用线程,而不是当需要执行任务就去创建线程、执行完毕就销毁线程,这样带来的系统开销太大。这也是线程池的基本思想。
  3. 此外,Java 只只支持单继承,如果继承 Thread 使用多线程,那么后续需要通过继承的方式扩展功能,那会相当麻烦。

2 start 和 run 方法

从上面可以得知,有两种创建线程的方式,我们通过 ​​Thread​​ 类或 ​​Runnable​​ 接口的 ​​run​​ 方法定义任务,通过 ​​Thread​​ 的 ​​start​​ 方法创建并启动线程。

❗❗ 我们不能通过 ​​run​​ 方法启动并创建一个线程,它只是一个普通方法,如果直接调用这个方法,其实只是调用这个方法的线程在执行任务罢了。

// 将上面的代码修改一下,查看执行结果
public class CreateOne {
public static void main(String[] args) {
Thread t = new MySubThread();
t.run();
//t.start();
}
}

// ===================== 执行结果
main执行任务

查看 start 方法的源码:

// 线程状态,为 0 表示还未启动
private volatile int threadStatus = 0;

// ❗❗ 同步方法,确保创建、启动线程是线程安全的
public synchronized void start() {
// 如果线程状态不为 0,那么抛出异常——

标签:总结,Java,Thread,中断,线程,sleep,多线程,方法,public
From: https://blog.51cto.com/u_15773567/5742948

相关文章

  • Class 7 视觉AI训练营参营总结与感想
    title:Class7参营总结与感想excerpt:达摩院特别版-视觉AI训练营tags:[阿里云,达摩院,AI,应用,视觉,oss存储,API,车辆部件识别,车辆损伤识别,车险图片......
  • Class 7 ECS 7天实践训练营参营总结与感想
    title:Class7参营总结与感想excerpt:云上实践云上成长ECS7天实践训练营tags:[阿里云,在家学习,进阶班]categories:[学习,阿里云]index_img:https://......
  • (总结)linux安装expect(包括gcc&tcl)
    1.安装gcc首先到​​http://vault.centos.org/6.3/os/x86_64/Packages/​​下载用到的rpm包,包括:ppl-0.10.2-11.el6.x86_64.rpm 、cloog-ppl-0.15.7-1.2.el6.x86_64.rpm 、......
  • Java Web中间件
    目录​​中间件​​​​常见的web中间件有哪些​​​​Tomcat​​​​Weblogic​​​​Jboss​​​​Jetty​​​​Webshere​​​​Glasshfish​​中间件我们经常会看到中......
  • Java Web 02
    DDL:操作数据库查询:showdatabases;-- 显示所有数据库 selectdatabase();--查询当前所使用的数据库创建:creatdatabase数据库名 ;creatdatabaseifno......
  • Linux中配置java环境
    本文所需的jdk1.8版本rpm包:链接:​​https://pan.baidu.com/s/146rZKd0hP0851MBT68PnEw​​ 提取码:uqif很多应用的运行需要有Java环境,如tomcat、amoeba等。首先查看......
  • C++多线程同步技巧(二) ---事件
    简介Windows在线程控制方面提供了多种信号处理机制,其中一种便是使用CreateEvent()函数创建事件,然后使用信号控制线程运行。其中将事件变为有信号可使用SetEvent()函数,将......
  • SpringBoot-JavaMailSender接口实战
    相信使用过Spring的众多开发者都知道Spring提供了非常好用的JavaMailSender接口实现邮件发送,在SpringBoot的Starter模块中也为此提供了自动化配置。下面通过实例来讲解如......
  • Java自定义注解实现权限管理
    前言Github地址:​​​https://github.com/erlieStar/authority_example​​源码定义权限注解@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public@int......
  • 阶段性总结
    前言上次写总结还是2021年末,本来应该等3个月后,2022年底做一个2022年终总结的,不过正好最近旧的工作告了一个段落,新的工作正要开始。那便以此为契机,做一下总结和进一步的规......