进程与线程
进程
- 程序由指令和数据组成,但这些指令要运行,数据要读写,就必须将指令加载至CPU,数据加载至内存,在指令运行过程中还需要用到磁盘,网络等设备,进程就是用来加载指令,管理内存,管理IO的
- 当一个程序被运行,从磁盘加载这个程序的代码至内存,这时就开启了一个进程
- 进程就可以视为程序的一个实例,大部分程序可以同时运行多个实例进程(;例如记事本,画图,浏览器等),也有的程序只能启动一个实例进程(例如网易云音乐,360安全卫士)
线程
- 一个进程之内可以分为一到多个线程
- 一个线程就是一个指令流,将指令流中的一条条指令以一定的顺序交给CPU执行
- java中,线程作为最小调度单位,进程作为资源分配的最小单位,在windows中进程是不活动的,只是作为线程的容器
进程与线程的区别
- 进程基本上相互独立的,而线程存在于进程内,是进程的一个子集
- 进程拥有共享的资源,如内存空间等,供其内部的线程共享
- 进程间通信较为复杂
- 同一台计算机的进程通信称为 IPC(Inter-process communication)
- 不同计算机之间的进程通信,需要通过网络,并遵守共同的协议,例如 HTTP
- 线程通信相对简单,因为它们共享进程内的内存,一个例子是多个线程可以访问同一个共享变量
- 线程更轻量,线程上下文切换成本一般上要比进程上下文切换低
并行与并发
并发
单核 cpu 下,线程实际还是串行执行的。操作系统中有一个组件叫做任务调度器,将cpu的时间片(windows下时间片最小约为 15 毫秒)分给不同的程序使用,只是由于 cpu 在线程间(时间片很短)的切换非常快,人类感觉是 同时运行的 。总结为一句话就是: 微观串行,宏观并行 , 一般会将这种 线程轮流使用 CPU 的做法称为并发, concurrent
并行
多核cpu下.每个
核(core)
都可以调度运行线程,这时候线程可以是并行的并行的级别
- 阻塞
- 指当一个线程进入临界区后,其他线程必须等待
- 非阻塞
- 无障碍(Obstruction-Free)
- 无障碍是一种最弱的非阻塞调度
- 线程可以自由进入临界区
- 进入临界区后,在无竞争时,有限步内完成对临界区资源的操作
- 有竞争时,回滚数据,放弃对临界区资源的操作
- 无锁(Lock-Free)
- 首先它是无障碍的
- 其次它保证所有进入临界区的线程有一个可以胜出
- 无等待(Wait-Free)
- 无锁的
- 要求所有的线程都必须在有限步内完成
- 无饥饿的
并行与并发区别
- 并行:指两个或多个事件在同一时刻发生(同时发生)。(双车道同时开过两辆车)
- 并发:指两个或多个事件在同一个时间段内发生。(单车道,先后开过两辆车)
查看进程线程的方法
windows
- 任务管理器可以查看进程和线程数,也可以杀死进程
tasklist
查看进程
taskkill
杀死进程
linux
ps -fe
查看所有进程
ps -fT -p <PID>
查看某个进程的所有线程
kill -9
杀死进程
top
按大写H切换是否显示线程
top -H -p <PID>
查看某个进程的所有线程
java
jps
命令查看所有java进程
jstack <PID>
查看某个Java进程的所有线程状态
jconsole
查看某个进程中线程的运行情况(图形界面)
jconsole远程监控配置
需要以如下方式运行你的 java 类
java -Djava.rmi.server.hostname=`ip地址` -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=`连接端口` -Dcom.sun.management.jmxremote.ssl=是否安全连接 -Dcom.sun.management.jmxremote.authenticate=是否认证 java类
修改
/etc/hosts
文件将 127.0.0.1 映射至主机名,映射至主机名如果要认证访问,还需要做如下步骤- 复制
jmxremote.password
文件
- 修改
jmxremote.password
和jmxremote.access
文件的权限为 600 即文件所有者可读写
- 连接时填入
controlRole
(用户名),R&D
(密码)
用户线程与守护线程
在Java中有两类线程:
User Thread
(用户线程或非守护线程)、Daemon Thread
(守护线程) ,只要当前JVM实例中尚存在任何一个非守护线程没有结束,守护线程就全部工作;只有当最后一个非守护线程结束时,守护线程随着JVM一同结束工作。
Daemon的作用是为其他线程的运行提供便利服务,守护线程最典型的应用就是 GC (垃圾回收器),它就是一个很称职的守护者。
User和Daemon两者几乎没有区别,唯一的不同之处就在于虚拟机的离开:如果
User Thread
已经全部退出运行了,只剩下Daemon Thread
存在了,虚拟机也就退出了。 因为没有了被守护者,Daemon也就没有工作可做了,也就没有继续运行程序的必要了。
@Slf4j(topic = "c.Test15") public class Test15 { public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(() -> { while (true) { if (Thread.currentThread().isInterrupted()) { break; } } log.debug("结束"); }, "t1"); //将t1设为守护线程 t1.setDaemon(true); t1.start(); Thread.sleep(1000); log.debug("结束"); } } //output //21:51:45.706 c.Test15 [main] - 结束
Tomcat中的
Acceptor
和Poller
线程都是守护线程,所以Tomcat接收到shutdown
命令后,不会等待它们处理完当前请求守护线程并非只有虚拟机内部提供,用户在编写程序时也可以自己设置守护线程:
Thread daemonTread = new Thread(); // 设定 daemonThread 为 守护线程,default false(非守护线程) daemonThread.setDaemon(true); // 验证当前线程是否为守护线程,返回 true 则为守护线程 daemonThread.isDaemon();
这里有几点需要注意:
thread.setDaemon(true)
必须在thread.start()
之前设置,否则会抛出一个IllegalThreadStateException
异常。你不能把正在运行的常规线程设置为守护线程。
- 在
Daemon
线程中产生的新线程也是Daemon
的。
- 不要认为所有的应用都可以分配给
Daemon
来进行服务,比如读写操作或者计算逻辑。
同步和异步
同步,可以理解为在执行完一个函数或方法之后,一直等待系统返回值或消息,这时程序是阻塞的,只有接收到返回的值或消息后才往下执行其他的命令。
异步,执行完函数或方法后,不必阻塞性地等待返回值或消息,只需要向系统委托一个异步过程,那么当系统接收到返回值或消息时,系统会自动触发委托的异步过程,从而完成一个完整的流程。
同步如打电话,通信双方不能断(我们是同时进行,同步),你一句我一句,这样的好处是,对方想表达的信息我马上能收到,但是,我在打着电话,我无法做别的事情。
异步如收发收短信,对比打电话,打电话我一定要在电话的旁边听着,保证双方都在线,而收发短信,对方不用保证此刻我一定在手机旁,同时,我也不用时刻留意手机有没有来短信。这样的话,我看着视频,然后来了短信,我就处理短信(也可以不处理),接着再看视频。