脚本宝典收集整理的这篇文章主要介绍了并发编程-进程和线程,脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。
程序由指令和数据组成,但这些指令要运行,数据要读写,就必须将指令加载至 CPU,数据加载至内存。在指令运行过程中还需要用到磁盘、网络等设备。进程就是用来加载指令、管理内存、管理 IO 的
当一个程序被运行,从磁盘加载这个程序的代码至内存,这时就开启了一个进程。 进程就可以视为程序的一个实例。大部分程序可以同时运行多个实例进程(例如记事本、画图、浏览器等),也有的程序只能启动一个实例进程(例如网易云音乐、360 安全卫士等)
一个进程之内可以分为一到多个线程。
一个线程就是一个指令流,将指令流中的一条条指令以一定的顺序交给 CPU 执行
Java 中,线程作为最小调度单位,进程作为资源分配的最小单位
。 在 windows 中进程是不活动的,只是作为线程的容器
同⼀个进程内多个线程之间可以共享代码段、数据段、打开的⽂件等资源
,但每个线程各⾃都有⼀套独⽴的寄存器和栈
,这样可以确保线程的控制流是相对独⽴的。
单核 cpu 下,线程实际还是串行执行
的。操作系统中有一个组件叫做任务调度器,将 cpu 的时间片(windows下时间片最小约为 15 毫秒)分给不同的程序使用,只是由于 cpu 在线程间(时间片很短)的切换非常快,人类感觉是 同时运行的 。总结为一句话就是: 微观串行,宏观并行
,
一般会将这种 线程轮流使用 CPU 的做法称为并发(concurrent)
多核 cpu下,每个 核(core)
都可以调度运行线程,这时候线程可以是并行的。
JMH
,即Java Microbenchmark Harness,是专门用于代码微基准测试的工具套件,它会执行程序预热,执行多次测试并平均
简单的来说就是基于方法层面的基准测试,精度可以达到微秒级。当你定位到热点方法,希望进一步优化方法性能的时候,就可以使用JMH对优化的结果进行量化的分析。
JMH比较典型的应用场景有:
生成项目模版
mvn archetype:generate -DinteractiveMode=false -DarchetypeGroupId=org.openjdk.jmh -DarchetypeArtifactId=jmh-java-benchmark-archetype -DgroupId=com.javaming.study -DartifactId=springboot-concurrent -Dversion=0.0.1-SNAPSHOT
ps -ef | grep redis # 查看redis进程
ps -fT -p <PID> # 查看某个进程(PID)的所有线程
top # 按1 显示每个CPU信息 再按切换回统计后CPU信息
top -H -p <PID> # 查看某个进程(PID)的所有线程
JVM 中由堆、栈、方法区所组成,其中栈内存是给谁用的呢?其实就是线程,每个线程启动后,虚拟机就会为其分配一块栈内存。 每个栈由多个栈帧(Frame)组成,对应着每次方法调用时所占用的内存 每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法
因为以下一些原因导致 cpu 不再执行当前的线程,转而执行另一个线程的代码
当 Context Switch 发生时,需要由操作系统保存当前线程的状态,并恢复另一个线程的状态,Java 中对应的概念就是程序计数器(Program Counter Register)
,它的作用是记住下一条 jvm 指令的执行地址,是线程私有的
Running
进入 Timed Waiting
状态(阻塞)Running
进入 Runnable
就绪状态,然后调度执行其它线程主线程中加入t1.join()后就必须等待 t1执行完才能继续运行
如果t1.join(1000) 指定等待1秒,则1秒后 j1就会打印会=0 如果t1.join(3000) 指定等待3秒,则2秒后 j1就会打印会=10
static int j1 = 0;
public static void main(String[] args) throws InterruptedException {
log.debug("开始运行");
Thread t1 = new Thread(() -> {
try {
sleep(2000);
j1 = 10;
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "t1");
t1.start();
//等待线程运行结束
t1.join(1000);
log.debug("结束运行 j1=" + j1);
}
private static void testInterrupt() throws InterruptedException {
Thread t1 = new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
// 打断休眠的线程 会清空打断状态
log.error("被打断 isInterrupt = " + Thread.currentThread().isInterrupted());
}
}, "t1");
t1.start();
Thread t2 = new Thread(() -> {
while (true) {
// 打断正常运行的线程 不会清空打断状态
boolean interrupted = Thread.currentThread().isInterrupted();
if(interrupted) {
log.error("被打断 isInterrupt = " + Thread.currentThread().isInterrupted());
break;
}
}
}, "t2");
t2.start();
TimeUnit.SECONDS.sleep(1);
log.debug("interrupt...");
t1.interrupt();
t2.interrupt();
}
和 interrupt 方法一样是判断当前线程是否被打断,但是这个方法是静态方法, 调用的时候会清除打断标记
查看打印结果可以知道:
在一个线程t1中如何优雅的停止线程t2?
如果使用stop()
方法: stop()方法会真正的杀死线程,如果线程锁住了共享资源,那么当他被杀死后就再也没有机会释放锁,其他线程永远无法获取锁
这个时候就依靠两阶段终止模式
来停止线程
public class TestStopThread {
private Thread monitorThread;
/**
* 开始监控线程
*/
public void start(){
monitorThread = new Thread(() -> {
while (true) {
boolean interrupted = Thread.currentThread().isInterrupted();
if(interrupted) {
log.debug("处理善后工作");
break;
}
try {
TimeUnit.SECONDS.sleep(2);
log.debug("执行监控工作");
} catch (InterruptedException e) {
}
}
}, "monitor");
monitorThread.start();
}
/**
* 停止监控线程
*/
public void stop(){
monitorThread.interrupt();
}
}
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
log.debug("park....");
LockSupport.park();
log.debug("unpark...");
log.debug("打断状态 = " + Thread.currentThread().isInterrupted());
LockSupport.park();
log.debug("unpark...");
}, "t1");
t1.start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
t1.interrupt();
}
可以看到即使重新LockSupport.park()
后 也无法生效 ,因为park只有 打断标记为false时才能继续生效
interrupt 打断park的锁时 打断标记置为true , 即使重新park 也不会生效
// log.debug("打断状态 = " + Thread.currentThread().isInterrupted());
log.debug("打断状态 = " + Thread.interrupted());
修改为上面的语句后就可以正常锁住线程
默认情况下,Java 进程需要等待所有线程都运行结束,才会结束。有一种特殊的线程叫做守护线程
,只要其它非守护线程运行结束了,即使守护线程的代码没有执行完,也会强制结束。
注意
垃圾回收器线程
就是一种守护线程Tomcat 中的 Acceptor 和 Poller
线程都是守护线程,所以 Tomcat 接收到 shutdown 命令后,不会等待它们处理完当前请求
以上是脚本宝典为你收集整理的并发编程-进程和线程全部内容,希望文章能够帮你解决并发编程-进程和线程所遇到的问题。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。