Java教程

2021-11-14 进程和线程(上下文切换)创建线程的方法

本文主要是介绍2021-11-14 进程和线程(上下文切换)创建线程的方法,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

进程和线程

一、进程

一个正在执行中的程序就是一个进程,系统会为这个进程发配独立的【内存资源】。进程是程序的一次执行过程,它有自己独立的生命周期,它会在启动程序时产生,运行程序时存在,关闭程序时消亡。
比如正在运行的QQ、IDEA、浏览器就是进程。

其实,谈及计算机时,永远不能简单的避开计算机的发展史。

最原始的计算机就是单进程的,同一时间只能执行一个进程,我们可以把现在的【计算器】当做最原始的计算机,同一时间只能执行一段代码。比如我们要计算一个账本的总账,只能一个数字一个数字的相加,而且,在这其中你还不能做其他的事情。

但是随着计算机的发展,计算任务的不断提升,单个进程的方式人们就很难接受了,与此同时cpu的计算能力也大幅提升,于是就产生了按照时间线交替执行不同进程的方式。 两个进程交替执行,每个执行一点点时间,在感觉上就像同时执行两个进程了。

如果一个进程有多个任务怎么办,比如我们使用浏览器同时下载八个小电影,一种方式是一个一个下载,一个完了下一个开始,另一种方式就是同时开始,最后一个下载完成结束。

第一种就是我们的串行执行,没什么好说的,第二种就需要其他的解决方案了,给每一个下载任务分配一个进程可以吗?每一个进程会分配独立的内存资源,原则上是可以的。
但是如果为每一个任务分配单独的进程去执行,进程间的通信就会不可避免,比如某一个下载任务完成了肯定要通知浏览器啊,这样就会产生一个问题,微信的进程是不是能访问QQ的进程?病毒是不是就很容易操作你运行中的进程,修改你的数据了。所以,在计算机的设计当中就引入了线程的概念。

二、线程

线程是由进程创建的,是进程的一个实体,是具体干活的人,一个进程可能有多个线程。线程不独立分配内存,而是共享进程的内存资源,线程可以共享cpu的计算资源。

现在,进程更强调【内存资源的分配】,而线程更强调【计算资源的分配】。因为有了线程的概念,一个进程的线程就不能修改另一个线程的数据,隔离性更好,安全性更好。

三、上下文切换

从任务管理器中我们可以看到,这台电脑上运行着263个进程,3670个线程,但是只有16个逻辑内核,这足以证明对于每一个逻辑内核他在执行的过程当中也是按照时间片执行不同的线程的。但是这里有几个问题:

  1. 我们的进程可以直接创建、调度线程吗?QQ运行了一会说我累了,不想执行了,微信你来吧!这显然是不合理的。
  2. QQ执行了一会,不执行了,那等其他线程执行完成之后,又轮上QQ了,QQ还能记得刚才运行到哪里了吗?

针对第一个问题,任何一个用户的线程是不允许调度其他的线程的,所有的线程调用都由一个大管家统一调度,这个大管家就是系统内核。

第二个问题,下一个执行时想要知道上一次的执行结果,就必须在上一次执行之后,讲运行时的数据进行保存。
在这里插入图片描述
其中,用户线程执行的过程我们称之为【用户态】,内核调度的状态称之为【内核态】,每一个线程运行时产生的数据我们称之为【上下文】,线程的每次切换都需要进行用户态到内核态的来回切换,同时伴随着上下文的切换,是一个比较消耗资源的操作,所以一个计算机当中不是线程越多越好,线程如果太多也是有可能拖垮整个系统的。

4、创建线程的方法

Java中创建线程的三种基本方式:

(1)继承Thread类重写run方法

步骤:

  • 定义类继承Thread;’
  • 重写Thread类中的run方法;(目的:将自定义代码存储在run方法中,让线程运行)
  • 调用线程的start方法:(该方法有两步:启动线程,调用run方法)
    在这里插入图片描述
    在这里插入图片描述

(2)实现Runnable接口

步骤:

  • 创建任务:创建类实现Runnable接口
  • 使用Thread为这个任务分配线程
  • 调用线程的start方法 在这里插入图片描述

(3)使用Lammbda表达式是(2)的简写

就是用箭头函数

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

(4)有返回值的线程

public class UseCallable {
	public static void main(String[] args) throws ExecutionException, InterruptedException {
		System.out.println(2);
		FutureTask<Integer> futureTask = new FutureTask<>(new Task());
		System.out.println(3);
		new Thread(futureTask).start();
		System.out.println(4);
		int result = futureTask.get();
		System.out.println(5);
		System.out.println(result);
		System.out.println(6);
	}
	static class Task implements Callable<Integer> {
		public Integer call() throws Exception {
			Thread.sleep(2000);
			return 1;
		}
	}
}

futureTask.get()会阻塞主线程,知道拿到返回值为止!
在这里插入图片描述
你可以自己控制结果的出现顺序!

这篇关于2021-11-14 进程和线程(上下文切换)创建线程的方法的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!