首页 > 编程语言 >Java线程的实践及原理揭秘

Java线程的实践及原理揭秘

时间:2024-08-27 08:53:13浏览次数:8  
标签:java Thread thread 线程 进程 Java 揭秘

Java线程的实践及原理揭秘

  • 并发是什么?
  • 系统支持高并发的因素是哪些?

1.如何理解系统的并发

一般来说,系统在单位时间内能够承载的并发数就是整个系统同事能够处理的请求数量。对于并发的指标通常通过TPS/QPS来表示

  • QPS:每秒处理的查询数(Queries-Per-Second)
  • TPS:每秒处理的事务数(Transactions-Per-Second)

2.系统如何支撑高并发

从一个完整架构来说,无非就是通过软件和硬件层面

硬件的组成CPU,网卡,带宽,磁盘,内存

对I/O性能要求比较高尽可能多的使用内存来存储,

对于运算性能比较高的,使用对线程处理

如果单个计算机硬件资源达到瓶颈,可以采用水平扩展的方式来提升性能。即横向增加服务器,利用多个计算机组成分布式计算机,当然,整个系统的复杂性增加,比如涉及服务治理,服务监控,服务的高可用。

对于一个高可用的应用来说,最大的问题就是如何让更多用户在最短时间内获取想要的信息及完成想要的操作,一般用RT(Reaction-Time)作为衡量指标

软件层面上的一些其他优化方案

  • 集群化部署
  • 多线程异步化
  • 缓存机制
  • CDN(内容分发网络)

3.线程的前世今生

线程是操作系统能够运算和调度的最小单元,一个进程可以创建多个线程,每个线程可以并行执行多个任务,并行执行的线程的数量是由CPU的核心数量来决定的。

利用多道程序和CPU时间片调度的方式让多个用户可以同时使用一台计算机的方式是分时系统即计算机对资源的一种共享方式

什么是多道程序?由于单个程序无法让CPU和I/O设备始终处于忙碌状态,所以操作系统允许同时加载多个程序到内存,也就是说可以同时启动多个进程,系统给这些进程分配独立的地址空间,以保证每个进程的地址不会相互干扰。

ulimit -n:查看进程能够并行处理的连接数

4.Java中如何使用多线程

在Java中实现多线程的方式有:

  • 继承Thread类
  • 实现Runnable接口
  • 使用ExecutorService线程池
  • 使用Callable/Future实现带返回值的多线程

5.多线程如何应用到实际场景

  • 网络请求分发场景
  • 文件导入处理的场景
  • 异步业务场景

Tomcat 7之后采用线程池改造的BIO,在Zookeeper,Nacos,Dubbo等中间件

6.多线程的基本原理

public class ThreadExample implements Runnable{


    @Override
    public void run() {
        System.out.println("Running");
    }

    public static void main(String[] args) {
         new Thread(new ThreadExample(),"THREAD-1").start();
    }
}
void Thread::start(Thread* thread) {
  trace("start", thread);
 
  if (!DisableStartThread) {
    if (thread->is_Java_thread()) {
      
      java_lang_Thread::set_thread_status(((JavaThread*)thread)->threadObj(),
                                          java_lang_Thread::RUNNABLE);
    }
    os::start_thread(thread);
  }
}

7.线程的运行状态

public enum State {

    // 新建状态,也就是说调用new Thread()时的状态
    NEW,

    // 运行状态,通过start()方法启动后的状态
    RUNNABLE,

    // 阻塞状态,执行Synchronized代码,并且未抢占到同步锁时,会变成该状态
    BLOCKED,

    // 调用Object.wait()等方法,会让线程变成该状态
    WAITING,

    // 超时等待状态,sleep(timeout),超时会自动唤醒
    TIMED_WAITING,

    // 终止状态,线程的run()方法中的指令执行完成后的状态
    TERMINATED;
}

TIME_WAITING状态演示

public class TimeWaitingStatusExample {

    public static void main(String[] args) {
        new Thread(()->{

            try {
                TimeUnit.SECONDS.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        ,"TIME_WAITING").start();
    }
}
E:\IDEA Space\school\thread-01\target\classes\cn\zhima>jps
7520 TimeWaitingStatusExample
17412 Launcher
19748 Jps
8932
8940 RemoteMavenServer

E:\IDEA Space\school\thread-01\target\classes\cn\zhima>jstack 7520
2023-08-05 10:21:12
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.121-b13 mixed mode):

"DestroyJavaVM" #13 prio=5 os_prio=0 tid=0x000000000134e800 nid=0x29ec waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"TIME_WAITING" #12 prio=5 os_prio=0 tid=0x000000001b816000 nid=0x46ec waiting on condition [0x000000001c08e000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
        at java.lang.Thread.sleep(Native Method)
        at java.lang.Thread.sleep(Thread.java:340)
        at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
        at cn.zhima.TimeWaitingStatusExample.lambda$main$0(TimeWaitingStatusExample.java:16)
        at cn.zhima.TimeWaitingStatusExample$$Lambda$1/990368553.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:745)
    

8.如何正确的终止线程

  • stop()
    • kill - 9
  • interrupt()
    • 设置中断标识,把run()中的指令执行完成,再完成线程中断的功能
    • 如果想把被阻塞的线程中断,则此线程需要先被唤醒,然后才能中断
void Thread::interrupt(Thread* thread) {
  trace("interrupt", thread);
  debug_only(check_for_dangling_thread_pointer(thread);)
  os::interrupt(thread);
}

void os::interrupt(Thread* thread) {
  assert(Thread::current() == thread || Threads_lock->owned_by_self(),
    "possibility of dangling Thread pointer");

   // 获取本地线程
  OSThread* osthread = thread->osthread();

  // 判断本地线程对象是否为中断状态
  if (!osthread->interrupted()) {
    // 设置中断标识为true
    osthread->set_interrupted(true);

    
    OrderAccess::fence();// 内存屏障,用来解决可见性问题
    
    // slp -> sleep  判断当前线程是否处于sleep状态,唤醒该线程
    ParkEvent * const slp = thread->_SleepEvent ;
    if (slp != NULL) slp->unpark() ;
  }

  
    //及时已经处于挂起状态的线程,也要进行唤醒 
  if (thread->is_Java_thread())
    ((JavaThread*)thread)->parker()->unpark();

  ParkEvent * ev = thread->_ParkEvent ;
  if (ev != NULL) ev->unpark() ;

}

volatile bool interrupted() const                 { return _interrupted != 0; }
void set_interrupted(bool z)                      { _interrupted = z ? 1 : 0; }

9.理解上下文切换带来的性能问题

为了支持更多的线程运行,CUP会把自己的时间片分配给其他线程,这个过程就是上下文切换

  • 进程上下文切换(进程的上下文切换,是指当前进程的CPU时间片分配给其他进程执行,进程切换分三种情况)
    • CUP时间片分配
    • 当进程系统资源不足,进程会被挂起
    • 当存在优先级更高的进程运行时,当前进程可能会被挂起,CPU时间片分配给优先级更高的进程运行
  • 线程上下文切换
    • 当两个线程切换属于不同的进程时,由于进程资源不共享,所以线程切换其实就是进程的切换
    • 当两个线程属于同一进程时,需要保存线程的上下文
  • 中断上下文切换
    • CPU本身故障,程序故障
    • I/O中断

如何减少上下文切换?

  • 减少进程数
  • 采用无锁的设计(CAS)

10.守护线程

thread.setDaemon(true);

应用场景:GC,事件监听,心跳检测

注意:线程状态的继承及thread.setDaemon(true);要写在start之前

11.快速定位并解决线程导致的生产问题

  1. 通过jps命令查看java进程的pid
  2. 通过jstack 命令查看线程的dump日志
  3. 如果是死锁—>Found one Java-level deadlock

标签:java,Thread,thread,线程,进程,Java,揭秘
From: https://blog.csdn.net/weixin_38121806/article/details/141587983

相关文章

  • 【网络编程通关之路】 Udp 基础回显服务器(Java实现)及你不知道知识原理详解 ! ! !
    本篇会加入个人的所谓鱼式疯言❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言而是理解过并总结出来通俗易懂的大白话,小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的.......
  • Java面试题--JVM大厂篇之JVM大厂面试题及答案解析(7)
           ......
  • javascript怎么实现链表?
    在JavaScript中实现链表通常涉及定义一个链表节点类(通常称为ListNode)和一个链表类(例如LinkedList),然后在这个链表类中实现各种操作链表的方法,如添加节点、删除节点、遍历链表等。以下是使用JavaScript实现单向链表的一个基本示例:链表节点类(ListNode)首先,我们定义一个链表节点......
  • 【Java】IDEA从零到一使用statemachine状态机模拟订单 (图解)
    Java系列文章目录补充内容Windows通过SSH连接Linux第一章Linux基本命令的学习与Linux历史文章目录Java系列文章目录一、前言二、学习内容:三、问题描述四、解决方案:4.1认识依赖4.2使用状态机4.2.1目录结构4.2.2状态机解析4.2.2.1概念4.2.2.2图解4.2.2.3拓展......
  • java连接sqlite数据库
    首先下载jar包(每种数据库有自己jar包)然后idea里创建新项目并且在项目里创建lib文件里面放jar包接着导入jar包然后apply->ok这样就连上如果要可视化数据库DBBrowser最后测试连接TestConnection看数据库连上没结果:......
  • java一键生成数据库说明文档html格式
    要验收项目了,要写数据库文档,一大堆表太费劲了,直接生成一个吧,本来想用个别人的轮子,网上看了几个,感觉效果不怎么好,自己动手写一个吧。抽空再把字典表补充进去就OK了先看效果:目录快速导航生成效果关键代码try{ StringprefixTables="sys_monitor_db_ha......
  • JAVA语言开发环境配置详细讲解
    ​​您好,我是程序员小羊!前言Java是一门广泛应用于软件开发领域的编程语言,自1995年由SunMicrosystems首次发布以来,经过多年的发展,已经成为业界的重要编程语言之一。Java以其“编写一次,到处运行”(WriteOnce,RunAnywhere)的理念,以及强大的库和工具支持,吸引了大量的开......
  • 学习笔记 韩顺平 零基础30天学会Java(2024.8.26)
    P536HMap阶段小结P537HMap底层机制     HashMap$Node($意思是一个内部类)实现了Map$Entry,因此HashMap$Node的底层可以看成是Map$Entry(对前面有关Entry那一节课的继续理解)P538HMap源码解读P539HMap扩容树化触发P540Hashtable使用     和HMap不同......
  • java 线程
    1.Java中有哪几种方式来创建线程执行任务1.继承Thread类(单继承)2.Runnable接口(没有继承限制)但是无法返回值3.callable接口结合FutureTask4.利用线程池来创建线程使用ExecutorService调用execute通过runnable创建底层都是基于runnable2.为什么不建议使用Executors来创建......
  • Java拼图小游戏
    登录界面注册界面游戏页面上代码App.javaimportcom.ui.GameJFrame;importcom.ui.LoginJFrame;importcom.ui.RegisterJFrame;publicclassApp{publicstaticvoidmain(String[]args){newLoginJFrame();//newGameJFrame();//......