本地门户网站系统,开通域名,wordpress怎么安装访问不了,黄石市城乡建设网站目录
一、前言
二、Linux查看进程、线程
2.1 Linux最大进程数
2.2 Linux最大线程数
2.3 Linux下CPU利用率高的排查
三、线程的实现
四、上下文切换
五、总结 一、前言
进程是程序执行相关资源#xff08;CPU、内存、磁盘等#xff09;分配的最小单元#xff0c;是一…目录
一、前言
二、Linux查看进程、线程
2.1 Linux最大进程数
2.2 Linux最大线程数
2.3 Linux下CPU利用率高的排查
三、线程的实现
四、上下文切换
五、总结 一、前言
进程是程序执行相关资源CPU、内存、磁盘等分配的最小单元是一系列线程的集合进程之间相互独立有自己的内存空间线程是CPU资源分配的最小单元线程需要的资源更少可以看做是一种轻量级的进程线程会共享进程中的内存但线程使用独立的栈、程序计数器线程相互通信更加方便。
在项目开发中经常会用到线程以及多线程功能来实现异步任务处理等。项目上线之后如果出现服务CPU高的异常情况那么这个时候就需要借助Linux因为一般情况服务都是使用Linux查看进程、线程来定位最终的问题。
二、Linux查看进程、线程
2.1 Linux最大进程数
Linux中进程可创建的实际值通过进程标识值process identification value-PID来标示可以使用
cat /proc/sys/kernel/pid_max 查看系统中可以创建的进程数实际值 可以使用ulimit命令修改最大限制值
ulimit -u 1024 如果要修改kernel.pid_max的值需要使用
sysctl -w kernel.pid_max1024
2.2 Linux最大线程数
用ulimit -s可以查看默认的线程栈大小一般情况下这个值是8M8192KB 不过Java程序受JVM堆空间的限制比如以下代码
public class ThreadExample extends Thread{public static void main(String[] args) {for(int i 0; i 100000; i){ThreadExample myThread new ThreadExample(i);myThread.start();}}private Integer threadNo;ThreadExample(Integer threadNo){threadNo threadNo;System.out.println(ThreadNo threadNo);}Overridepublic void run(){while (true){try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}
在idea上设置-Xmx1m启动运行程序创建出部分线程后会报OutOfMemoryError错误 2.3 Linux下CPU使用率高的排查
示例代码如下这段代码可以明显判断出来在while(true){count;}的地方会占用很高的CPU使用率那么如果代码已经上线了在生产上我们如何来判断哪里出问题了呢
public class CpuRatioExample extends Thread{private Integer count 0;public static void main(String[] args) {CpuRatioExample cpuRatioExample new CpuRatioExample();cpuRatioExample.start();}Overridepublic void run(){while(true){count;}}
}
第一步运行编译后的class
java CpuRatioExample 程序运行之后我们发现CPU使用率过高这个时候我们需要排查是哪个代码导致的一般情况生产系统上都会做CPU、磁盘等基础设施的监控。
第二步CPU使用率过高排查
top 命令查看哪个进程CPU使用率高 使用top命令发现 PID 1822的CPU占用异常再进一步查找哪个线程导致的
top -H -p pid 可以查看哪个线程cpu过高 第三步使用jstack命令保存栈信息
jstack 1822 1822.stack
并分析栈信息查找 1878线程对应的栈信息 stack信息是以16进制显示的 所以需要将CPU使用率高的线程1878转换为十六进制 756定位到在CpuRationExample的17行代码运行结合源代码定位了最终问题。 三、线程的实现
3.1 单线程的实现方式
3.1.1 Thread
public class ThreadExample extends Thread{public static void main(String[] args) {for(int i 0; i 100000; i){ThreadExample myThread new ThreadExample(i);myThread.start();}}private Integer threadNo;ThreadExample(Integer threadNo){threadNo threadNo;System.out.println(ThreadNo threadNo);}Overridepublic void run(){while (true){try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}
这种方式很简单但是不支持多重继承所以不能继承其他类。
3.1.2 Runnable
public class ThreadExample implements Runnable{public static void main(String[] args) {for(int i 0; i 100000; i){ThreadExample myThread new ThreadExample(i);new Thread(myThread).start();}}private Integer threadNo;ThreadExample(Integer threadNo){threadNo threadNo;System.out.println(ThreadNo threadNo);}Overridepublic void run(){while (true){try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
} 这种方式比继承Thread类更灵活因为一个类可以实现多个接口。 3.1.3 FetureTask
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;public class ThreadExample {public static void main(String[] args) {FutureTaskInteger futureTask new FutureTask(() - {// 异步执行的任务return 1;});new Thread(futureTask).start();try {// 获取异步执行的结果int result futureTask.get();System.out.println(result result);} catch (InterruptedException | ExecutionException e) {// 处理异常}}
}
3.2 线程池的实现方式
有关线程池的后续再详细介绍。
3.2.1 使用Executors类创建线程池
Executors.newFixedThreadPool(int nThreads)创建一个固定大小的线程池。 Executors.newCachedThreadPool()创建一个可以缓存线程的线程池。 Executors.newSingleThreadExecutor()创建一个单线程化的线程池。 3.2.2 使用ThreadPoolExecutor类创建线程池
ThreadPoolExecutor是一个更底层的类允许开发者更精细地控制线程池的行为比如
ThreadPoolExecutor executor new ThreadPoolExecutor( 5, // corePoolSize 10, // maximumPoolSize 60L, // keepAliveTime TimeUnit.SECONDS, // unit new LinkedBlockingQueueRunnable() // workQueue
); 四、上下文切换
多线程和单线程的选择往往取决于具体的应用场景和需求单线程是一次只做一件事按照顺序执行而多线程可以同时处理多个任务抢占更多的系统资源但是也会出现上下文切换有些时候多线程的性能未必比单线程要好。比如以下这段代码
public class DemoApplication {public static void main(String[] args) {//运行多线程MultiThreadTester test1 new MultiThreadTester();test1.Start();//运行单线程SerialTester test2 new SerialTester();test2.Start();}static class MultiThreadTester extends ThreadContextSwitchTester {Overridepublic void Start() {long start System.currentTimeMillis();MyRunnable myRunnable1 new MyRunnable();Thread[] threads new Thread[3];//创建多个线程for (int i 0; i 3; i) {threads[i] new Thread(myRunnable1);threads[i].start();}for (int i 0; i 3; i) {try {//等待一起运行完threads[i].join();} catch (InterruptedException e) {e.printStackTrace();}}long end System.currentTimeMillis();System.out.println(multi thread exce time: (end - start) ms);System.out.println(counter: counter);}// 创建一个实现Runnable的类class MyRunnable implements Runnable {public void run() {while (counter 100000000) {synchronized (this) {if(counter 100000000) {increaseCounter();}}}}}}//创建一个单线程static class SerialTester extends ThreadContextSwitchTester{Overridepublic void Start() {long start System.currentTimeMillis();for (long i 0; i count; i) {increaseCounter();}long end System.currentTimeMillis();System.out.println(serial exec time: (end - start) ms);System.out.println(counter: counter);}}//父类static abstract class ThreadContextSwitchTester {public static final int count 100000000;public volatile int counter 0;public int getCount() {return this.counter;}public void increaseCounter() {this.counter 1;}public abstract void Start();}
} 这段代码的测试结果是单线程的性能高于多线程的性能其主要原因就是多线程的上下文切换导致性能降低。
如果想要进一步分析上下文切换情况可以使用vmstat和pidstat分析上下文切换情况。 五、总结
本文介绍了进程和线程的区别以及Java如何开发单线程、多线程linux下最大进程数、线程数的限制以及如何通过jstack排查CPU使用率高的问题。后续将专门针对多线程开发进行介绍。