Java多线程编程(1)

Java多线程编程(1),第1张

0 基础概念

并行:指多个任务同时执行而不是交替执行。

并发:指一段时间内以交替的方式去完成多个任务。

       处理器可以以时间片分配的技术来实现同一段时间运行多个线程。因此,一个处理企就可以实现并发,而并行则需要靠多个处理器在同一时刻各自运行一个线程来实现。

多线程编程的好处:

  • 提高系统的吞吐率:多线程编程可以在一个进程中处理多个并发的 *** 作,比如一个线程因为IO *** 作而处于等待时,其他线程仍然可以执行其它 *** 作。
  • 提高响应性能:在使用多线程情形下,慢的 *** 作可能并不会影响其它的 *** 作,比如web请求总,一个慢的请求处理并不会影响其他请求的处理。
  • 充分利用多核处理器资源:适当的多线程分布可以充分利用处理器资源。
  • 最小化对系统资源的使用:相对多进程而言,一个进程中的多个线程可以共享其所申请的资源,比如内存。

多线程编程可能碰到的问题:

  • 线程安全:多个线程共享数据时,如果没有采取相应的并发访问控制措施,可能会产生数据一致性问题,如读取脏数据即过期数据、丢失更新(某线程的更新被其他线程的更新所覆盖)等。
  • 线程活性:死锁(指两个或两个以上的线程或进程在运行过程中,因为资源竞争而造成相互等待的现象,若无外力作用则不会解除等待状态,它们之间的执行都将无法继续下去)、活锁(指正在执行的线程或进程没有发生阻塞,但由于某些条件没有满足,导致反复重试-失败-重试-失败的过程。与死锁最大的区别在于:活锁状态的线程或进程是一直处于运行状态的,在失败中不断重试,重试中不断失败,一直处于所谓的“活”态,不会停止)、饥饿(指一条长时间等待的线程无法获取到锁资源或执行所需的资源,而后面来的新线程反而“插队”先获取了资源执行,最终导致这条长时间等待的线程出现饥饿)。
  • 上下文切换:处理器从执行一个线程转向执行另外一个线程的时候 *** 作系统所做的动作被称为上下文切换。
1 Java线程       

       在Java中创建一个线程就是创建一个Thread类(或其子类)的实例。每个线程都有其执行的任务,线程的任务处理逻辑可以在Thread类的run方法中直接实现或者通过该方法调用相关处理函数,因此run方法相当于线程的任务处理逻辑的入口方法,它由Java虚拟机在运行相应线程时直接调用,而不是由应用代码进行调用。

       运行一个线程实际上就是让Java虚拟机执行该线程的run方法,从而使该线程的任务处理逻辑得以执行。Thread类的start方法可以启动一个线程。启动一个线程的实质是请求Java虚拟机运行相应的线程,而这个线程具体何时能够运行时由线程调度器Scheduler决定的。因此,start方法调用结束并不意味着相应线程已经开始运行,这个线程可能稍后才能运行,也可能永远也不会被运行。

       Java平台中的线程不是孤立的,线程与线程之间存在一定的联系,比如父子关系。main方法中直接创建的线程都是main线程的子线程,这些子线程所执行的代码也可以创建其他线程。有些情况下也会称这些子线程为工作者线程(worker thread)或者后台线程(background thread)。工作者线程通常是其父线程创建来用于专门负责执行某项特定任务的执行的。在Java中,一个线程的优先级默认为其父线程的优先级

2 线程创建

       Thread类的两个常用构造函数是:Thread()和Thread(Runnable target)。相应地,Java语言中创建线程有两种方式:

  • 一种是使用上述第1个构造器,定义Thread类的子类,在子类中覆盖(Override)run方法并在该方法中实现线程任务处理逻辑;
  • 另一种是使用上述第2个构造器,创建一个java.lang.Runnable接口的实例,并在该实例的run方法中实现任务处理逻辑,然后以该Runnable接口实例作为构造器的参数直接创建(new)一个Thread的实例。

以下代码演示以下如何使用这两种方法创建线程(没有考虑竞态条件)。


public class ThreadCreation {
    public static void main(String[] args){
        TaskCountRunnable taskCountRunnable = new TaskCountRunnable();
        final int threadNum = Runtime.getRuntime().availableProcessors();
        
        for(int i=0;i命令作用格式jps列出正在运行的虚拟机进程jps [ option ] [ hostid ]jstat监视jvm各种运行状态信息的命令行工具。可以显示本地或者远程虚拟机进程中的类加载、内存、垃圾收集、即时编译等运行时数据。jstat [option vmid [ interval [s/ms] [count] ] ]jinfo实时查看和调整虚拟机的各项参数jinfo [option] pidjmap用于生成堆转储快照(一般成为heapdump或者dump文件)jmap [option] pidjstack用于生成虚拟机当前时刻的线程快照(一般成为ThreadDump或者javacore文件)。线程快照就是当前虚拟机内每一条线程正在执行的方法堆栈集合,生成快照的目的一般都是用于定位线程出现长时间的停顿原因,比如死锁、死循环、阻塞等。jstack [option] pidjhat与jmap搭配使用,用来分析jmap生成的堆转储快照文件内容。但是在实际工作中,不建议使用这个工具,可以选择其他可视化工具进行离线分析。jhat从JDK9的时候已经删除了(JEP 241: Remove the jhat Tool)。现在Oracle官方推荐的分析工具是Eclipse Memory Analyzer Tool (MAT) 和 VisualVM。

其它工具箱:

JC console:JConsole(Java Monitoring and Managermen Console)是一款基于JMX(Java Managemen Extensions)的可视化监视、管理工具。

直接在windows版的jdk/bin目录下,运行jconsole.exe

VisualVM:VisualVM(All-in-One Java Troubleshooting Tool)具有功能:

  • 显示虚拟机进程以及进程的配置、环境信息(jps、jinfo);
  • 监视应用程序的处理器、垃圾收集、堆、方法区以及线程的信息(jstat、jstack);
  • dump以及分析堆转储快照(jmap、jhat);
  • 方法级的程序运行性能分析,找出被调用最多、运行时间最长的方法;
  • 离线程序快照:收集程序运行时配置、线程dump、内存dump等信息建立一个快照,可以将快照发送开发者进行bug反馈。
  • 使用其他插件来扩展功能。

       此工具同样在jdk/bin目录下,直接运行jvisualvm.exe文件。上文中使用jmap工具dump出来的demodump.bin文件,使用jvisualvm就可以打开分析。

Arthas:arthas是阿里开源的Java诊断工具,当你遇到以下类似问题而束手无策时,Arthas可以帮助你解决:Arthas 用户文档 — Arthas 3.6.1 文档

  •  这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?

  • 我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?

  • 遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?

  • 线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!

  • 是否有一个全局视角来查看系统的运行状况?

  • 有什么办法可以监控到JVM的实时运行状态?

  • 怎么快速定位应用的热点,生成火焰图?

  • 怎样直接从JVM内查找某个类的实例? 

Arthas支持JDK 6+,支持Linux/Mac/Windows,采用命令行交互模式,同时提供丰富的 Tab 自动补全功能,进一步方便进行问题的定位和诊断

TMDA:IBM Thread and Monitor Dump Analyzer for Java (TMDA) 是允许识别 Java 线程转储中的挂起、死锁、资源争用和瓶颈的工具。IBM Thread and Monitor Dump Analyzer for Java (TMDA)

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/801830.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-07
下一篇 2022-05-07

发表评论

登录后才能评论

评论列表(0条)