线程与协程

Java中的线程

Java线程如何实现

以HotSpot为例,它的每一个Java线程都是直接映射到一个操作系统的原生线程来实现的,而且中间没有额外的简介结构,所以HotSpot自己是不会去干涉线程调度的(可以设置线程优先级给操作系统提供调度建议),全权交给操作系统去处理,所以何时冻结或唤醒线程、该给线程分配多少处理器执行时间,该把线程安排给哪个核心处理器去执行等,都是由操作系统完成的,也都是由操作系统全权决定的。

Java线程调度

线程的调度方式有两种:协同式线程调度和抢占式调度。

协同式的好处:实现简单,而且由于线程要把自己的事情处理完才会进行线程切换,所以一般没有什么线程同步的问题。坏处:线程的执行时间不可控制,如果有一个线程的代码有问题,且一直不通知系统进行线程切换那么程序就会一直阻塞在那里。

Java中使用的是抢占式调度,每个线程由系统来分配执行时间,线程的切换不由线程本身来决定。虽说Java中的线程调度是由处理器完成的,但我们仍然可以“建议”操作系统给某些线程多分配一些执行时间,另外的线程少分配一些执行时间——这个操作是通过设置线程的优先级来实现的。Java语言中一共设置了10个级别的线程优先级(Thread.MAX_PRIORITY 到 Thread.MIN_PRIORITY), 方法源码如下:

public final void setPriority(int newPriority) {
        ThreadGroup g;
        checkAccess();
        if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
            throw new IllegalArgumentException();
        }
        if((g = getThreadGroup()) != null) {
            if (newPriority > g.getMaxPriority()) {
                newPriority = g.getMaxPriority();
            }
            setPriority0(priority = newPriority);
        }
    }

状态转换

Java语言定义了线程的六种状态,在任一时间点,线程有且只能有一种状态,并且可以通过特定的方法在不同状态之间转换:

新建(New):创建后尚未启动的线程处于这种状态;

运行(Runnable):包括操作系统线程状态中的Running和Ready,也就是处于此状态的线程有可能正在被执行,也有可能正在等待着操作系统为它分配执行时间。

无限期等待(Waiting):处于这种状态的线程不会被分配处理器执行时间,他们要等待被其他线程显式唤醒。以下方法会让线程陷入无限期的等待状态:

  • 没有设置Timeout参数的Object::wait()方法;
  • 没有设置Timeout参数的Thread::join()方法;
  • LockSupprot::park() 方法;

限期等待(Timed Waiting):处于这种状态的线程也不会被分配处理器执行时间,不过无需等待被其他线程显式唤醒,在一定时间以后它们会由系统自动唤醒。以下方法会让线程进入限期等待状态:

  • Thread::sleep() 方法;
  • 设置了Timeout参数的Object::wait()方法;
  • 设置Timeout参数的Thread::join()方法;
  • LockSupport::parkNanos() 方法;
  • LockSupport::parkUntil() 方法;

阻塞(Blocked):线程被阻塞了,“阻塞状态”与“等待状态”的区别是

阻塞状态在等待着获取到一个排它锁,这个事件将在另外一个线程放弃这个锁的时候发生;而等待状态则是等待一段时间,或者唤醒动作的发生。在程序等待进入同步区域的时候,线程将进入这种状态。

结束(Terminated):已终止现成的线程状态,线程已经结束执行。

以上6中状态在遇到特定事件发生的时候会互相转换,如下图所示:

在这里插入图片描述

Java与协程

现代B/S系统中一次对外部请求的响应,往往需要分布在不同机器上的大量服务共同协作来实现,这种服务细分的架构在减少单个服务复杂度,增加复用性的同时,也不可避免地增加了服务的数量,缩短了留给每个服务的响应时间。1:1的内核线程模型是如今Java虚拟机线程实现的主流选择,但是这种映射到操作系统上的线程天然的缺陷是切换、调度成本较高,系统能容纳的线程数量也有限。

协程就是由用户自己来模拟多线程。其中大致的原理是通过在内存中划出一片额外空间来模拟调用栈,只要其他“线程”中方法压栈、出栈是遵守规则,不破坏这片空间即可,这样多段代码执行时就会像相互缠绕着一样,非常形象。

后来,操作系统开始提供多线程的支持,靠应用自己模拟多线程的做法自然是变少了,但并未完全消失,而是演化为用户线程继续存在。由于最初多数的用户线程是被设计成协同式调度的,所以又叫做“协程”。

拟多线程的做法自然是变少了,但并未完全消失,而是演化为用户线程继续存在。由于最初多数的用户线程是被设计成协同式调度的,所以又叫做“协程”。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值