Java从入门到精通十二(java线程)【上】

简介: 计算机操作系统的有关线程和进程的浅显说明按照操作系统的理解,进程是操作系统分配资源的基本单位。线程是调度资源的基本单位。有很多形象的比喻,其实还是抽象化了。抽象化隐藏细节,实现似乎具体的可观。这样就是帮助理解。是在软件层次上的理解。把一个进程比作一个车间,然后车间的工人就是就相当于线程,然后其实多线程的化,你就向大的级别进行,多线程就是相当于一个大厂,然后大厂里的多个车间就是进程。进程是车间,车间的资源提供给线程进行共享。然后执行每个零碎的任务。

计算机操作系统的有关线程和进程的浅显说明

按照操作系统的理解,进程是操作系统分配资源的基本单位。

线程是调度资源的基本单位。


有很多形象的比喻,其实还是抽象化了。抽象化隐藏细节,实现似乎具体的可观。这样就是帮助理解。是在软件层次上的理解。


把一个进程比作一个车间,然后车间的工人就是就相当于线程,然后其实多线程的化,你就向大的级别进行,多线程就是相当于一个大厂,然后大厂里的多个车间就是进程。进程是车间,车间的资源提供给线程进行共享。然后执行每个零碎的任务。


一种非常标准的说法就是,进程就是程序的一次执行。打开一个程序,然后一个或者多个进程就开始了。然后这个程序具体功能的实现还是需要线程去具体实现的。


尽管这样说明,但是其实相信好多人还是和我有好多的疑问。因为根本的底层我们是不太理解的,或者是不理解。我的模电数电,组成原理没学好。汇编,操作系统的系统支撑了我的一些二对于底层的模糊认识。


在电脑上,我们在任务管理器可以直接查看进程。

所以说这些执行程序都可以认为是进程,基本的执行进程下面都有相应的线程。



还可以设置优先级



还可以设置哪些处理器运行指定的进程。



我的cpu不是八核的,这里是虚拟出来的,实际上只有四个内核。因为是intel,采用了超线程技术。



有的进程执行的时候只含有一个线程。举个例子。栗子很多,那么你到底想吃哪个?

开启一个终端,就是开启这样一个cmd.exe。cmd.exe是比较简单的程序,所以只需要这样一个线程。这也说明了它的功能就是比较单一的。等待用户输入命令,然后执行。



但是并不是一直一个,我在观察的时候会发现有时候会出现四个线程。我观察到,过一会儿会有规律的变成一个线程,即使我在终端执行命令,有时候它还是一个线程。


上面我们说了,线程就像车间忙碌的工人,大一点的程序一定会有多条线程的。


这样告诉我线程数就完了吗?我还想比较直观的看到线程的参数,以及优先级,我还想看到它的状态。


系统是一定会让你在终端查看进程的。我要先看进程。为什么我要先看进程,因为我可以通过进程的标识,查看它下面对应的进程。




提供一些参数


Pri:优先级

Thd:线程数

Hnd:句柄数

VM:虚拟内存

WS:工作集

Priv:专用虚拟内存

Priv Pk:专用虚拟内存峰值

Faults:页面错误

NonP:非页面缓冲池

Page:页面缓冲池

Cswtch:上下文切换


简单了解一下就可以,来举这个例子就是为了直观看到这些线程。感受一下。操纵系统中常说的阻塞或者排队状态,上面也给出了标识。


页面错误在组成原理提到过


若进程欲访问的页面目前并未驻留在内存中,将会发生页面错误


页面错误很正常,这里代表缺页。当发生缺页后,就会触发页面错误

当你的进程某些数据的页面长时间不被访问后,Windows将把它们从内存置换到硬盘上,常用的那些页面则常驻内存。但是需要用到那些数据的时候,发现内存中没有那些页面,就发生缺页中断,然后从硬盘上把那些页面调入。


我清楚的记得组成原理有提到过。果然听听还是有很大用的。


java执行方面的进程和线程的体现

我们会想到java基本的运行机制



java源代码首先需要通过java编译器编译为字节码文件(.class文件),字节码文件是一种二进制的文件,里面的数据紧密相连。文件的内容比较紧凑。字节码文件时通过javac .exe生成,然后再java.exe的作用下进行启动虚拟机(jvm),执行字节码。虚拟机会将编译好的字节码文件加载到内存(也就是类加载。然后虚拟机会对这个类加载的文件进行解释执行。)

直接由虚拟机进行解释执行,而并非操作系统。这样特点也决定了它的跨平台(java程序通过jvm实现)。


jvm也是一个软件层次的程序,在功能的实现上,具有自己完整的堆栈存储区,数据存储区这些,计数器等等。因此有时候也可以被认为是一个小型的计算机。但是这些都是虚拟出来的,实在软件的层次上虚拟出来的功能架构。


jvm是用来具体执行java程序的。jvm执行的时候本身也是一个进程的的进程。并且它是一个多线程对我进程。因为jvm需要做一些事情来支持java的运行机制。


所以jvm本身就是一个多线程的应用。从我们执行程序的main方法入口开始。jvm程序需要执行的时候,操作系统将jvm从磁盘存储器将其调入到内存中,然后创建一个jvm的进程。jvm启动主线程,主线程调用类的main方法,所以主线程也就是从main方法这里开始执行了。既然是一个多线程的应用,那么除了主线程以外还有其它的线程。


比如比较经典的垃圾回收机制的GC thread,此类线程主要进行对JVM里面的垃圾进行收集。再比如字节码编译的线程Compiler threads,再比如给jvm收集信号的线程Singal dispatcher thread。


好奇线程是如何调用的,实现的底层是什么?这就给自己又添麻烦了。


自己去查看start()这个启动的源码



这个函数的里面调用的另一个函数start0才应该是真正启动线程的。底层还是c++写的。native修饰说明是调用了原生系统函数。我去看了看,觉得还是挺复杂的。用notepad打开比较快一点



一个jvm.cpp就将近四千行代码,所以我大致看了几个函数就走了。再见!


参考了网上的一些说明,大致都是在说明方法调用逻辑。


线程启动过程。这是在c++源码上来说的。



说明:该图来自

小傅哥

CodeGuide | 程序员编码指南 Go! - 沉淀、分享、成长,让自己和他人都能有所收获!


此文有对源码,以及具体执行过程的一些探索。


java自己携带了一个可视化的工具,可以动态的观察一下cpu占用,堆,线程的情况。当然这些不是目前主要去看的,主要用在后面的性能调优上面。


VisualVM,java自带的一个监控工具


主要可以分析数据,跟踪内存泄漏,监控垃圾回收,执行内存等等的操作。


直接在控制台运行jvisualvm,大体就是这个界面。当然可以去进行远程连接,查看资源情况等等。





当你在运行一个程序的时候,比较大的一个程序,可以去看看jvm的堆占用情况。


java线程

Thread类信息摘要

public class Threadextends Objectimplements Runnable

线程 是程序中的执行线程。Java 虚拟机允许应用程序并发地运行多个执行线程。


创建新执行线程有两种方法。一种方法是将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法。接下来可以分配并启动该子类的实例。


创建线程的另一种方法是声明实现 Runnable 接口的类。该类然后实现 run 方法。然后可以分配该类的实例,在创建 Thread 时作为一个参数来传递并启动。


每个线程都有一个标识名,多个线程可以同名。如果线程创建时没有指定标识名,就会为其生成一个新名称。


一:嵌套类说明


public static enum Thread.Stateextends Enum<Thread.State>


该类的枚举常量说明了线程的状态


BLOCKED

受阻塞并且正在等待监视器锁的某一线程的线程状态。

NEW

至今尚未启动的线程的状态。

RUNNABLE

可运行线程的线程状态。

TERMINATED

已终止线程的线程状态。

TIMED_WAITING

具有指定等待时间的某一等待线程的线程状态。

WAITING

某一等待线程的线程状态。


另外一个嵌套类


public static interface Thread.UncaughtExceptionHandler


这是一个接口


当 Thread 因未捕获的异常而突然终止时,调用处理程序的接口。


当某一线程因未捕获的异常而即将终止时,Java 虚拟机将使用 Thread.getUncaughtExceptionHandler() 查询该线程以获得其 UncaughtExceptionHandler 的线程,并调用处理程序的 uncaughtException 方法,将线程和异常作为参数传递。如果某一线程没有明确设置其 UncaughtExceptionHandler,则将它的 ThreadGroup 对象作为其 UncaughtExceptionHandler。如果 ThreadGroup 对象对处理异常没有什么特殊要求,那么它可以将调用转发给默认的未捕获异常处理程序。


二:主要的一些字段


static int MAX_PRIORITY

线程可以具有的最高优先级。

static int MIN_PRIORITY

线程可以具有的最低优先级。

static int NORM_PRIORITY

分配给线程的默认优先级。


优先级可以自己进行设定,有一个范围,也可以去获取运行线程的优先级。


三:构造方法


Thread()

分配新的 Thread 对象。

Thread(Runnable target)

分配新的 Thread 对象。

Thread(Runnable target, String name)

分配新的 Thread 对象。

Thread(String name)

分配新的 Thread 对象。

Thread(ThreadGroup group, Runnable target)

分配新的 Thread 对象。

Thread(ThreadGroup group, Runnable target, String name)

分配新的 Thread 对象,以便将 target 作为其运行对象,将指定的 name 作为其名称,并作为 group 所引用的线程组的一员。

Thread(ThreadGroup group, Runnable target, String name, long stackSize)

分配新的 Thread 对象,以便将 target 作为其运行对象,将指定的 name 作为其名称,作为 group 所引用的线程组的一员,并具有指定的堆栈大小。

Thread(ThreadGroup group, String name)

分配新的 Thread 对象。


四:方法


static int activeCount()

返回当前线程的线程组中活动线程的数目。

void checkAccess()

判定当前运行的线程是否有权修改该线程。

int countStackFrames()

已过时。 该调用的定义依赖于 suspend(),但它遭到了反对。此外,该调用的结果从来都不是意义明确的。

static Thread currentThread()

返回对当前正在执行的线程对象的引用。

void destroy()

已过时。 该方法最初用于破坏该线程,但不作任何清除。它所保持的任何监视器都会保持锁定状态。不过,该方法决不会被实现。即使要实现,它也极有可能以 suspend() 方式被死锁。如果目标线程被破坏时保持一个保护关键系统资源的锁,则任何线程在任何时候都无法再次访问该资源。如果另一个线程曾试图锁定该资源,则会出现死锁。这类死锁通常会证明它们自己是“冻结”的进程。有关更多信息,请参阅为何不赞成使用 Thread.stop、Thread.suspend 和 Thread.resume?。

static void dumpStack()

将当前线程的堆栈跟踪打印至标准错误流。

static int enumerate(Thread[] tarray)

将当前线程的线程组及其子组中的每一个活动线程复制到指定的数组中。

static Map<Thread,StackTraceElement[]> getAllStackTraces()

返回所有活动线程的堆栈跟踪的一个映射。

ClassLoader getContextClassLoader()

返回该线程的上下文 ClassLoader。

static Thread.UncaughtExceptionHandler getDefaultUncaughtExceptionHandler()

返回线程由于未捕获到异常而突然终止时调用的默认处理程序。

long getId()

返回该线程的标识符。

String getName()

返回该线程的名称。

int getPriority()

返回线程的优先级。

StackTraceElement[] getStackTrace()

返回一个表示该线程堆栈转储的堆栈跟踪元素数组。

Thread.State getState()

返回该线程的状态。

ThreadGroup getThreadGroup()

返回该线程所属的线程组。

Thread.UncaughtExceptionHandler getUncaughtExceptionHandler()

返回该线程由于未捕获到异常而突然终止时调用的处理程序。

static boolean holdsLock(Object obj)

当且仅当当前线程在指定的对象上保持监视器锁时,才返回 true。

void interrupt()

中断线程。

static boolean interrupted()

测试当前线程是否已经中断。

boolean isAlive()

测试线程是否处于活动状态。

boolean isDaemon()

测试该线程是否为守护线程。

boolean isInterrupted()

测试线程是否已经中断。

void join()

等待该线程终止。

void join(long millis)

等待该线程终止的时间最长为 millis 毫秒。

void join(long millis, int nanos)

等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒。

void resume()

已过时。 该方法只与 suspend() 一起使用,但 suspend() 已经遭到反对,因为它具有死锁倾向。有关更多信息,请参阅为何不赞成使用 Thread.stop、Thread.suspend 和 Thread.resume?。

void run()

如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。

void setContextClassLoader(ClassLoader cl)

设置该线程的上下文 ClassLoader。

void setDaemon(boolean on)

将该线程标记为守护线程或用户线程。

static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)

设置当线程由于未捕获到异常而突然终止,并且没有为该线程定义其他处理程序时所调用的默认处理程序。

void setName(String name)

改变线程名称,使之与参数 name 相同。

void setPriority(int newPriority)

更改线程的优先级。

void setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)

设置该线程由于未捕获到异常而突然终止时调用的处理程序。

static void sleep(long millis)

在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。

static void sleep(long millis, int nanos)

在指定的毫秒数加指定的纳秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。

void start()

使该线程开始执行;Java 虚拟机调用该线程的 run 方法。

void stop()

已过时。 该方法具有固有的不安全性。用 Thread.stop 来终止线程将释放它已经锁定的所有监视器(作为沿堆栈向上传播的未检查 ThreadDeath 异常的一个自然后果)。如果以前受这些监视器保护的任何对象都处于一种不一致的状态,则损坏的对象将对其他线程可见,这有可能导致任意的行为。stop 的许多使用都应由只修改某些变量以指示目标线程应该停止运行的代码来取代。目标线程应定期检查该变量,并且如果该变量指示它要停止运行,则从其运行方法依次返回。如果目标线程等待很长时间(例如基于一个条件变量),则应使用 interrupt 方法来中断该等待。有关更多信息,请参阅为何不赞成使用 Thread.stop、Thread.suspend 和 Thread.resume?。

void stop(Throwable obj)

已过时。 该方法具有固有的不安全性。有关详细信息,请参阅 stop()。该方法的附加危险是它可用于生成目标线程未准备处理的异常(包括若没有该方法该线程不太可能抛出的已检查的异常)。有关更多信息,请参阅为何不赞成使用 Thread.stop、Thread.suspend 和 Thread.resume?。

void suspend()

已过时。 该方法已经遭到反对,因为它具有固有的死锁倾向。如果目标线程挂起时在保护关键系统资源的监视器上保持有锁,则在目标线程重新开始以前任何线程都不能访问该资源。如果重新开始目标线程的线程想在调用 resume 之前锁定该监视器,则会发生死锁。这类死锁通常会证明自己是“冻结”的进程。有关更多信息,请参阅为何不赞成使用 Thread.stop、Thread.suspend 和 Thread.resume?。

String toString()

返回该线程的字符串表示形式,包括线程名称、优先级和线程组。

static void yield()

暂停当前正在执行的线程对象,并执行其他线程。


以上引用摘自javaapi


具体的使用说明的话,将说明总结一些比较常用的方法进行举例代码。


相关文章
|
8天前
|
Java 开发者
Java多线程编程中的常见误区与最佳实践####
本文深入剖析了Java多线程编程中开发者常遇到的几个典型误区,如对`start()`与`run()`方法的混淆使用、忽视线程安全问题、错误处理未同步的共享变量等,并针对这些问题提出了具体的解决方案和最佳实践。通过实例代码对比,直观展示了正确与错误的实现方式,旨在帮助读者构建更加健壮、高效的多线程应用程序。 ####
|
15天前
|
安全 Java 测试技术
Java并行流陷阱:为什么指定线程池可能是个坏主意
本文探讨了Java并行流的使用陷阱,尤其是指定线程池的问题。文章分析了并行流的设计思想,指出了指定线程池的弊端,并提供了使用CompletableFuture等替代方案。同时,介绍了Parallel Collector库在处理阻塞任务时的优势和特点。
|
6天前
|
安全 Java 开发者
Java 多线程并发控制:深入理解与实战应用
《Java多线程并发控制:深入理解与实战应用》一书详细解析了Java多线程编程的核心概念、并发控制技术及其实战技巧,适合Java开发者深入学习和实践参考。
|
7天前
|
Java 开发者
Java多线程编程的艺术与实践####
本文深入探讨了Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的技术文档,本文以实战为导向,通过生动的实例和详尽的代码解析,引领读者领略多线程编程的魅力,掌握其在提升应用性能、优化资源利用方面的关键作用。无论你是Java初学者还是有一定经验的开发者,本文都将为你打开多线程编程的新视角。 ####
|
6天前
|
存储 安全 Java
Java多线程编程中的并发容器:深入解析与实战应用####
在本文中,我们将探讨Java多线程编程中的一个核心话题——并发容器。不同于传统单一线程环境下的数据结构,并发容器专为多线程场景设计,确保数据访问的线程安全性和高效性。我们将从基础概念出发,逐步深入到`java.util.concurrent`包下的核心并发容器实现,如`ConcurrentHashMap`、`CopyOnWriteArrayList`以及`BlockingQueue`等,通过实例代码演示其使用方法,并分析它们背后的设计原理与适用场景。无论你是Java并发编程的初学者还是希望深化理解的开发者,本文都将为你提供有价值的见解与实践指导。 --- ####
|
12天前
|
安全 Java 开发者
深入解读JAVA多线程:wait()、notify()、notifyAll()的奥秘
在Java多线程编程中,`wait()`、`notify()`和`notifyAll()`方法是实现线程间通信和同步的关键机制。这些方法定义在`java.lang.Object`类中,每个Java对象都可以作为线程间通信的媒介。本文将详细解析这三个方法的使用方法和最佳实践,帮助开发者更高效地进行多线程编程。 示例代码展示了如何在同步方法中使用这些方法,确保线程安全和高效的通信。
36 9
|
9天前
|
安全 Java 开发者
Java多线程编程中的常见问题与解决方案
本文深入探讨了Java多线程编程中常见的问题,包括线程安全问题、死锁、竞态条件等,并提供了相应的解决策略。文章首先介绍了多线程的基础知识,随后详细分析了每个问题的产生原因和典型场景,最后提出了实用的解决方案,旨在帮助开发者提高多线程程序的稳定性和性能。
|
15天前
|
存储 安全 Java
Java多线程编程的艺术:从基础到实践####
本文深入探讨了Java多线程编程的核心概念、应用场景及其实现方式,旨在帮助开发者理解并掌握多线程编程的基本技能。文章首先概述了多线程的重要性和常见挑战,随后详细介绍了Java中创建和管理线程的两种主要方式:继承Thread类与实现Runnable接口。通过实例代码,本文展示了如何正确启动、运行及同步线程,以及如何处理线程间的通信与协作问题。最后,文章总结了多线程编程的最佳实践,为读者在实际项目中应用多线程技术提供了宝贵的参考。 ####
|
11天前
|
监控 安全 Java
Java中的多线程编程:从入门到实践####
本文将深入浅出地探讨Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的摘要形式,本文将以一个简短的代码示例作为开篇,直接展示多线程的魅力,随后再详细解析其背后的原理与实现方式,旨在帮助读者快速理解并掌握Java多线程编程的基本技能。 ```java // 简单的多线程示例:创建两个线程,分别打印不同的消息 public class SimpleMultithreading { public static void main(String[] args) { Thread thread1 = new Thread(() -> System.out.prin
|
15天前
|
Java
JAVA多线程通信:为何wait()与notify()如此重要?
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是实现线程间通信的核心机制。它们通过基于锁的方式,使线程在条件不满足时进入休眠状态,并在条件满足时被唤醒,从而确保数据一致性和同步。相比其他通信方式,如忙等待,这些方法更高效灵活。 示例代码展示了如何在生产者-消费者模型中使用这些方法实现线程间的协调和同步。
28 3
下一篇
无影云桌面