JAVA19虚拟线程以及原理

虚拟线程介绍

很多语言都有类似于“虚拟线程”的技术,比如Go、C#、Erlang、Lua等,他们称之为“协程”。

不管是虚拟线程还是协程,他们都是轻量级线程,其目的都是为了提高并发能力。 本节详细介绍Java平台的“虚拟线程”的技术——“JEP 425: Virtual Threads (Preview)”。

Java平台计划引入虚拟线程,可显著减少编写、维护和观察高吞吐量并发应用程序的工作量。“JEP 425: Virtual Threads (Preview)”目是一个预览性的API。

示例代码

public static void main(String[] args) throws InterruptedException {

		final List<Thread> threadList = IntStream.range(0, 10000).mapToObj(index -> Thread.ofVirtual().unstarted(() -> {
			//打印线程
			if (index == 0) {
				System.out.println(Thread.currentThread());
			}
			//休眠
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				throw new RuntimeException(e);
			}
			//打印线程
			if (index == 0) {
				System.out.println(Thread.currentThread());
			}


		})).collect(Collectors.toList());

		threadList.forEach(Thread::start);
		for (Thread thread : threadList) {
			thread.join();
		}
		//SpringApplication.run(DemoApplication.class, args);
	}

运行结果

在这里插入图片描述
这里我们可以看到,java虚拟线程实际上使用了ForkJoinPool线程池。

在这里插入图片描述
这个时候大家就有疑问了为 什么休眠10毫秒过后,第2次打印的线程是 worker-2 ?
实际上,它可以从一个平台线程跳转到另一个,如果你在自己的电脑上操作,请确保有足够的虚拟线程, 如果只有一两个线程,是无法观测到这一点的。

这里发生了什么? 虚拟线程是如何从一个线程跳转到另一个线程的? 其实没什么魔法,核心就是一个名为Continuation的对象。
下面我带大家看看Thread.sleep的源码

在这里插入图片描述
可以看到,这里对 VirtualThread做了特殊的处理,如果是虚拟线程会调用 vthread.sleepNanos(nanos); 方法
在 doSleepNanos中调用了 tryYield()方法
在这里插入图片描述
在这里插入图片描述
在tryYield()里面调用了yieldContinuation()方法,yieldContinuation()方法里面调用了Continuation.yield(VTHREAD_SCOPE);
这就是奇迹发生的地方,这个Continuation对象是它的核心
在这里插入图片描述

Continuation对象是如何工作的

在这里插入图片描述
运行上面代码前,还需要在vm中加入 --add-opens java.base/jdk.internal.vm=ALL-UNNAMED,
上述代码运行结果:
在这里插入图片描述
大家可以看到,这个Continuation对象上调用run方法,只会执行Continuation的Runnable, 但这其实并不是我们想要的。
下面我将上面的方法做一下调整调用yield方法

	ContinuationScope scope = new ContinuationScope("scope");

		Continuation continuation = new Continuation(scope, () -> {
			System.out.println("Running");
			Continuation.yield(scope);
			System.out.println("yield Running");
		});
		System.out.println("start");
		continuation.run();
		System.out.println("stop");

运行结果:
在这里插入图片描述
神奇的事情出现了,yield Running并没有被打印,证明 Continuation.yield(scope); 后面的方法没有被执行。

实际上Continuation.yield(scope); 会暂停它的执行。 , 接下来我将再次调用continuation.run();看看会发生什么?

		ContinuationScope scope = new ContinuationScope("scope");

		Continuation continuation = new Continuation(scope, () -> {
			System.out.println("Running");
			Continuation.yield(scope);
			System.out.println("yield Running");
		});
		System.out.println("start");
		continuation.run();
		System.out.println("back");
		continuation.run();
		System.out.println("stop");

打印结果:
在这里插入图片描述
可以看到,再次运行run方法, 打印了yield Running

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值