Java多线程基础知识

1. 进程 | 线程、并行 | 并发

  • 软件(Software):一系列按照特定顺序组织的计算机数据和指令的集合。有系统软件和应用软件之分。
  • 程序(Program):为完成特定任务、用某种语言编写的一组指令的集合,指一段静态的代码,是静态对象。
  • 进程(Process):程序的一次执行过程,或是正在运行的一个程序,是一个动态的过程。进程是操作系统资源分配的基本单位。
  • 线程(Thread):一个程序内部的一条执行路径。线程是处理器任务调度和执行的基本单位(最小单元)。
  • 并行(Parallel):多个CPU同时执行多个任务。两个或多个事件在同一时刻发生。
  • 并发(Concurrent):单个CPU(采用时间片)同时执行多个任务。两个或多个事件在同一时间段内发生。

Java程序是运行在JVM上面的,每一个JVM其实就是一个进程。所有的资源分配都是基于JVM进程来的。而在这个JVM进程中,又可以创建出很多线程,多个线程之间共享JVM资源,并且多个线程可以并发执行。

每个线程拥有独立的运行栈和程序计数器,线程切换的开销小。一个进程中的多个线程共享相同的内存单元/内存地址空间,它们从同一堆中分配对象,可以访问相同的变量和对象,这就使得线程间通信更简便、高效。但多个线程操作共享的系统资源可能就会带来安全隐患(线程安全问题)。在JVM中,Java堆和方法区的区域是多个线程共享的数据区域,多个线程可以操作保存在堆或者方法区中的同一个数据,保存在堆和方法区中的变量就是Java中的共享变量。

  • 类变量:存放在JVM的方法区中
  • 成员变量:存放在JVM的堆内存中
  • 局部变量:存放在JVM的栈内存中

进程和线程的区别

  • 进程是一个独立的运行环境,而线程是在进程中执行的一个任务。他们两个本质的区别是是否单独占有内存地址空间及其它系统资源(比如I/O)
  • 系统在运行时会为每个进程分配不同的内存区域,进程单独占有一定的内存地址空间,所以进程间存在内存隔离,数据是分开的,数据共享复杂但是同步简单,各个进程之间互不干扰;而线程共享所属进程占有的内存地址空间和资源,数据共享简单,但是同步复杂。
  • 进程单独占有一定的内存地址空间,一个进程出现问题不会影响其他进程,不影响主程序的稳定性,可靠性高;一个线程崩溃可能影响整个程序的稳定性,可靠性较低。
  • 进程单独占有一定的内存地址空间,进程的创建和销毁不仅需要保存寄存器和栈信息,还需要资源的分配回收以及页调度,开销较大;线程只需要保存寄存器和栈信息,开销较小。
  • 进程是操作系统进行资源分配的基本单位,而线程是操作系统进行调度的基本单位,即CPU分配时间的单位 。

多进程的方式也可以实现并发,为什么我们要使用多线程?

  • 进程间的通信比较复杂,而线程间的通信比较简单,通常情况下,我们需要使用共享资源,这些资源在线程间的通信比较容易。
  • 进程是重量级的,而线程是轻量级的,故多线程方式的系统开销更小。

进程调度算法:

  • 先到先服务
  • 短作业优先
  • 时间片轮转
  • 优先级调度
  • 多级反馈队列(既能使高优先级的作业得到响应,又能使短作业进程迅速完成。)

Java的线程调度方法:

  • 同优先级线程组成先进先出队列(先到先服务),使用时间片策略;
  • 高优先级的线程的调度策略采用抢占式,优先级高的线程比优先级低的线程会有更大的几率优先执行。

对于单CPU的计算机来说,在任意时刻只能执行一条机器指令,每个线程只有获得CPU的使用权才能执行指令;所谓多线程的并发运行,其实是指从宏观上看,各个线程轮流获得CPU的使用权,分别执行各自的任务。线程的运行状态中包含两种子状态,即就绪(READY)和运行中(RUNNING),而一个线程想要从就绪状态变成运行中状态,这个过程需要系统调度,即给线程分配CPU的使用权,获得CPU使用权的线程才会从就绪状态变成运行状态。给多个线程按照特定的机制分配CPU的使用权的过程就叫做线程调度

守护线程 VS 用户线程

  • 它们几乎在每个方面都是相同的,唯一的区别是判断 JVM 何时离开。
  • 守护线程是用来服务用户线程的,通过在 start() 方法前调用 thread.setDaemon(true) 可以把一个用户线程变成一个守护线程。
  • 在 Daemon 线程中产生的新线程也是 Daemon 线程。
  • Java 垃圾回收就是一个典型的守护线程。
  • 若 JVM 中都是守护线程,当前 JVM 将退出。JVM 退出时守护线程中的 finally 块并不一定会执行。

单核CPU,其实是一种假的多线程,因为在一个时间单元内,也只能执行一个线程的任务。但是因为CPU时间单元特别短,因此感觉不出来。如果是多核CPU的话,才能更好的发挥多线程的效率。以单核CPU为例,只使用单个线程先后完成多个任务(调用多个方法),肯定比用多个线程来完成用的时间更短,为何仍需多线程呢?

  1. 提高应用程序的响应。对图形化界面更有意义,可增强用户体验。
  2. 提高计算机系统CPU的利用率。
  3. 改善程序结构,将既长又复杂的进程分为多个线程,独立运行,利于理解和修改。

何时需要多线程?

  • 程序需要同时执行两个或多个任务。
  • 程序需要实现一些需要等待的任务时,如:用户输入、文件读写操作、网络操作、搜索等。
  • 需要一些后台运行的程序时。
  • 一个 Java 应用程序 java.exe,至少有三个线程:main() 主线程、gc() 垃圾回收线程、异常处理线程。
  • 使用多线程的原因:更多的处理器核心、更快的响应时间、更好的编程模型。
package com.thread.java;

import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;

/**
 * @author rrqstart
 * @Description 一个普通的Java程序包含的线程
 */
public class MultiThread {
   
    public static void main(String[] args) {
   
        //获取Java线程管理MXBean
        ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
        //不需要获取同步的monitor和synchronizer信息,仅获取线程和线程堆栈信息
        ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false, false);
        //遍历线程信息,仅打印线程ID和线程名称
        for (ThreadInfo threadInfo : threadInfos) {
   
            System.out.println(threadInfo.getThreadId() + " : " + threadInfo.getThreadName());
        }
    }
}
//程序执行结果:
6 : Monitor Ctrl-Break //监控Ctrl-Break中断信号
5 : Attach Listener //该线程用于JVM进程间的通信,但是它不一定会启动
4 : Signal Dispatcher //分发处理发送给JVM信号的线程
3 : Finalizer //调用对象的finalize方法的线程
2 : Reference Handler //清除Reference的线程
1 : main //main线程,用户程序的入口

2. 线程的创建和使用

Java 语言的 JVM 允许程序运行多个线程,它通过 java.lang.Thread 类来体现。

package java.lang; //since JDK1.0

public class Thread implements Runnable {
   

    private Runnable target;

	public Thread(Runnable target) {
   
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }
    private void init(ThreadGroup g, Runnable target, String name, long stackSize) {
   
        init(g, target, name, stackSize, null, true);
    }
    private void init(Thre
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值