欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 金融 > 线程和进程(juc)

线程和进程(juc)

2025/8/11 21:20:25 来源:https://blog.csdn.net/2301_79748665/article/details/144299259  浏览:    关键词:线程和进程(juc)

线程

一:概念辨析

1:线程与进程

进程:

1:程序由指令和数据组成,指令要执行,数据要读写,就需要将指令加载给cpu,把数据加载到内存,同时程序运行时还会使用磁盘,网络等资源。进程就是负责管理内存,加载指令,管理io的;

2:当一个程序运行时就会将程序的相关代码加载到内存中,这就开启了一个进程;

3:一个程序的实例就是进程,有的程序可以有多个实例进程,有的程序只能有一个实例进程;


线程:

1:一个进程内会有一个或多个线程

2:一个线程就是一个指令流,将指令一条条按照顺序加载给cpu执行;

3:在java中,线程是最小调度单位,进程是最小资源管理单位。在windows中进程是不活动的只是作为线程的容器;


线程和进程对比:

1:进程是相对独立的,线程存在于进程,是进程的一个子集;

2:进程有共享的资源,如共享的内存;

3:进程间的通信,分为同一个计算机和不同计算机:

同一个计算机进行通信较为简单,称为ipc;

不同计算机的进程进行通信需要借助于网络,并且遵守相同的协议如http;

4:线程间通信较为简单,因为他们共享进程的资源;

5:线程更轻量,线程切换上下文比进程切换上下文的成本更低;

2:并发和并行的概念:

并发:在单核cpu下线程实际上是串行执行的,操作系统中有个组件叫任务调度器,它会将cpu的时间片轮流交给不同的线程使用,由于时间片很短,cpu在不同的线程进行切换人类感知不到,所以就会感觉是同时运行的。总结一下就是:微观串行,宏观并行

像这种,线程轮流使用cpu的情况就叫做并发;

而在多核cpu下,每个核都可以调度线程,这个时候就是并行的;

使用golang的创作者的一句话就是:并发:是同时应对多件事的能力;(deal with)

并行:是同时做多件事的能力;(do)

二:应用

1:异步调用:

同步调用:需要等待结果返回才能执行下面的代码;

异步调用:无需等待结果的返回就能执行下面的代码;

2:提升效率:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

注意单核cpu使用多线程与单核cpu使用单线程的性能差距不是很大;

多核cpu和单核cpu执行的性能有很大差别;

三:创建

1:使用thread的内部类

public static void main(String[] args) {Thread t=new Thread(){@Overridepublic void run() {log.debug("new thread");}};t.setName("t1");t.start();log.debug("main");
}

t.setName(“t1”);来给线程命名。run方法指定要执行的任务,start启动线程;

2:使用runnable配合thread

将线程和任务分开:runnable来定义任务,thread创建线程:

public static void main(String[] args) {Runnable runnable= new Runnable(){@Overridepublic void run() {log.debug("running");}};Thread thread = new Thread(runnable);thread.setName("t1");thread.start();log.debug("running");
}

java8之后可以使用lamda表达式来简化语句:

public static void main(String[] args) {/* Runnable runnable= new Runnable(){@Overridepublic void run() {log.debug("running");}};*/Runnable runnable =() ->log.debug("running");Thread thread = new Thread(runnable);thread.setName("t1");thread.start();log.debug("running");
}

或者:

public static void main(String[] args) {/* Runnable runnable= new Runnable(){@Overridepublic void run() {log.debug("running");}};*//*   Runnable runnable =() ->log.debug("running");*/Thread thread = new Thread(()->log.debug("running"),"t1");/*thread.setName("t1");*/thread.start();log.debug("running");
}

3:使用futureTask配合thread

public static void main(String[] args) throws ExecutionException, InterruptedException {FutureTask<Integer> integerFutureTask = new FutureTask<Integer>(new Callable<Integer>() {@Overridepublic Integer call() throws Exception {log.debug("running");return 100;}});Thread thread=new Thread(integerFutureTask,"t1");thread.start();log.debug("{}",integerFutureTask.get());}

futuretask继承了runnable接口,futuretask能够接收callable参数;

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

调用get方法时会阻塞等待,等待线程执行完毕然后返回结果;

四:查看

1:windows

window查看进程:

  • 使用任务管理器查看
  • 命令行:tasklist:查看所有进程
  • 杀死进程:taskkill

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2:linux

linux查看进程:

  • ps命令,结合管道运算符。
  • top命令动态的查看进程;

杀死进程:

  • kill 【进程id】

查看线程:

  • top -H -p 【进程id】

-H表示查看线程,-p指定进程id;

3:java

  • 查看进程:jps
  • 查看线程:jstack 【进程id】

五:原理

上下文切换

  • 什么是线程的上下文切换:

    当cpu暂停执行当前线程,开始执行下一个线程的时候会产生上下文切换;

  • 什么情况下会导致上下文切换

    1:cpu的时间片用完

    2:垃圾回收

    3:优先级更高的线程执行;

    4:主动调用一些方法如sleep,yield,join,wait,lock等

    当上下文切换时就需要保存当前线程的状态,并且恢复另一个线程的状态。jvm有一个组件叫程序计数器,它的作用是来记录下一条指令的执行地址,程序计数器是线程私有的;

    保存线程的状态不止程序计数器,还需要保存虚拟机栈中的栈帧信息;

    频繁的上下文切换会影响性能;

六:常见方法

1:start和run方法

start:

public static void main(String[] args) {new Thread(()->log.debug("start"),"t1").start();
}

结果:

16:20:03.992 [t1] DEBUG org.example.Field.test1 - start

run:

public static void main(String[] args) {new Thread(()->log.debug("run"),"t1").run();
}

结果:

16:22:07.587 [main] DEBUG org.example.Field.test1 - run

可以看到run没有创建一个新的线程,没法达到异步调用的效果;start可以;

start不能调用多次,不然会报错。

2:sleep

1:状态:
public static void main(String[] args) {Thread t1 = new Thread(() -> {try {Thread.sleep(2000);} catch (InterruptedException e) {throw new RuntimeException(e);}}, "t1");t1.start();log.debug("state:{}",t1.getState());try {Thread.sleep(500);} catch (InterruptedException e) {throw new RuntimeException(e);}log.debug("state:{}",t1.getState());
}

输出:

16:32:08.998 [main] DEBUG org.example.Field.test2 - state:RUNNABLE
16:32:09.512 [main] DEBUG org.example.Field.test2 - state:TIMED_WAITING

可以看到,调用sleep方法之后线程会进入time-waiting状态;

那个线程里调用sleep,那个线程就休眠

2:打断

调用interrupt方法可以打断休眠的线程,但是会抛出异常:

public static void main(String[] args) {Thread t1 = new Thread(() -> {try {Thread.sleep(2000);} catch (InterruptedException e) {throw new RuntimeException(e);}}, "t1");t1.start();log.debug("state:{}",t1.getState());try {Thread.sleep(500);} catch (InterruptedException e) {throw new RuntimeException(e);}t1.interrupt();log.debug("state:{}",t1.getState());
}

结果:

16:36:26.912 [main] DEBUG org.example.Field.test2 - state:RUNNABLE
16:36:27.416 [main] DEBUG org.example.Field.test2 - state:TIMED_WAITING
Exception in thread "t1" java.lang.RuntimeException: java.lang.InterruptedException: sleep interruptedat org.example.Field.test2.lambda$main$0(test2.java:18)at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.InterruptedException: sleep interruptedat java.base/java.lang.Thread.sleep(Native Method)at org.example.Field.test2.lambda$main$0(test2.java:16)... 1 more
3:yield和sleep的区别

调用yield后线程的状态会从running状态转变为runnable就绪状态状态,然后去调用其他线程;具体的实现依赖于操作系统的任务调度器

和sleep的区别是,调用sleep进入time-wait状态不会被cpu调用,而调用yield进入就绪状态还是有可能被cpu调用的;

3:线程优先级

  • 线程的优先级会提示调度器优先执行该线程,但是只是一个提示,调度器可以忽略;
  • 当cpu较忙时会给优先级高的线程分配较长的时间片,cpu较闲时,优先级几乎没有作用;

4:join

join:等待线程运行结束;

join(时间):设置最大等待时间,如果超过最大等待时间则不再等待,如果没超过就执行完毕直接返回;

5:interrupt

打断线程

1:打断阻塞:

打断sleep,wait,join的线程;

打断后会抛出异常;

然后打断标记会变成true;

2:打断正常:

打断正常的线程不会使线程停止运行,只会将打断标记变为true;

public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(() -> {while (true) {}}, "t1");thread.start();Thread.sleep(1000);log.debug("interrupt");thread.interrupt();log.debug("is,{}",thread.isInterrupted());
}
18:43:44.479 [main] DEBUG org.example.Field.test3 - interrupt
18:43:44.481 [main] DEBUG org.example.Field.test3 - is,true

但是会一直执行;

可以进行判断然后打断线程:

public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(() -> {while (true) {Thread thread1 = Thread.currentThread();if (thread1.isInterrupted()) {log.debug("被打断了");break;}}}, "t1");thread.start();Thread.sleep(1000);log.debug("interrupt");thread.interrupt();log.debug("is,{}",thread.isInterrupted());
18:48:49.671 [main] DEBUG org.example.Field.test3 - interrupt
18:48:49.672 [t1] DEBUG org.example.Field.test3 - 被打断了
18:48:49.672 [main] DEBUG org.example.Field.test3 - is,true
``

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词