汕头市通信建设管理办公室网站,怎么查看网站打开速度,原画师,上海本地app有哪些一、线程的实现 
线程的实现方式主要有三种#xff1a;内核线程实现、用户线程实现、用户线程加轻量级进程混合实现。因为自己只对java的线程比较熟悉一点#xff0c;所以主要针对java线程和go的协程之间进行一个对比。 线程模型主要有三种#xff1a;1、内核级别线程#…一、线程的实现 
线程的实现方式主要有三种内核线程实现、用户线程实现、用户线程加轻量级进程混合实现。因为自己只对java的线程比较熟悉一点所以主要针对java线程和go的协程之间进行一个对比。 线程模型主要有三种1、内核级别线程2、用户级别线程3、混合线程 1、内核级别线程 内核级别线程就是直接由操作系统的内核kernel支持的线程这种方式实现的线程主要通过内核的调度器来进行调度由内核完成线程切换。一般来讲程序不会直接调用系统内核线程而是利用内核线程的一种高级接口-轻量级进程Light Weight Process,即LWP它也可以视为用户线程也就是我们平时所说的线程每一个LWP都是由一个内核线程支持也就是先有内核线程再有LWP。这种LWP与内核线程之间1:1的关系称为一对一线程模型这是一种最简单的线程实现方式。见下图 2018-11-16 22-40-01 的屏幕截图.png 这种方式创建的每一个线程都需要由一个内核线程支持需要消耗一定的内核资源因此一个系统支持的线程数量是有限的。另外由于基于内核线程实现这种方式创建的线程操作需要进行系统调用而系统调用代价较高需要在用户态和内核态进行切换这个我也不懂。 2、用户级别线程 这里所指的用户级线程主要是创建在用户空间的线程库上系统内核感受不到线程的实现方式。用户线程的建立、同步、销毁等在用户态中完成不需要内核的介入。这种进程和用户线程UT之间1:N的关系称为一对多线程模型。 1321313.jpg 这种方式的优势就是上下文切换比较快缺点是无法从多线程处理器或多处理器计算机上的硬件加速中受益同时调度的线程永远不会超过一个。 3、混合线程 这种方式相当于是第一种方式和第二种方式的混合即有LWT也有用户线程这种方式中用户线程UT和LWT的数量比是不定的即所谓的N:M关系也就是所谓的多对多模型。这种实现线程的方式相比前两种也更为复杂这种方式中由线程库负责在可用的可调度实体上调度用户线程这使得线程的上下文切换非常快因为它避免了系统调用。但是增加了复杂性和优先级倒置的可能性以及在用户态调度程序和内核调度程序之间没有广泛且高昂协调的次优调度。 3213213123.jpg 
java线程实现 
主要说下常用的hotspot的JVM采用的是第一种1:1的线程模型即map a java thread to a native thread也就是说java线程会和native线程有个一一映射的关系如果看下java的Thread类就可以发现有很多的native方法这就涉及到操作系统的线程了。 
二、go语言并发模式 
go语言支持两种并发模式一种是Communicating Sequential ProcessesCSP模式这种模式中值是在相互独立的协程goroutine中传递的协程和协程之间使用到就是上次说到的channel。另外一种就是我们比较传统的模式也是我们相对熟悉的模式Share Memory Multithreading。但是go语言推荐的还是第一种模式go官网文档是说Do not communicate by sharing memory; instead, share memory by communicating.也就是说不建议线程或协程之间通过共享内存通讯而是通过通讯共享内存。比方说比较熟悉的java其实就是共享内存模式的并发模式在涉及到多线程的问题时必须考虑共享数据的安全性。 
三、线程和协程之间的区别 
这里说的协程指的只是go语言的goroutine。线程和协程的区别主要是数量上的而不是性质上所以说协程从逻辑上来说也是线程。 
栈的大小 
1、线程栈 操作系统的线程一般都分配有一块固定大小的内存块一般来说大小是2M这个需要查证我查找资料显示的64位Linux上hotspot虚拟机的栈的大小默认为1M地址https://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html。。栈存储的是方法的局部变量或者一些基本数据类型java中。因为栈的大小是固定的在执行某些方法的时候可能就不太够用比如一些比较复杂或则一些深的递归操作比如熟悉的java有时候会有栈溢出异常当然某些时候2M可能显得有点大这样从一定程度上来说又造成了浪费。 2、协程 协程开始的时候也会分配一定大小的内存区域一般只有2K和线程的栈一样协程的栈存储的也是局部变量但是不同的是协程的栈的大小是不固定的是可以根据需要自动调整大小的最大甚至可以达到1G所以灵活性非常好。 
调度方式 
1、系统级别的线程是由操作系统的内核(kernel)调度的每过几毫秒硬件的计时器就会中断处理器从而引起被成为调度器的内核函数执行。调度器会暂停当前正在执行的线程并把它的寄存器存到内存中并查看线程列表决定接下来执行哪一个线程然后从内存中恢复改线程的寄存器最后恢复该线程的执行。因为线程是通过内核调度的从一个线程切换到另一个线程就涉及到上下文转换建议看下维基百科https://en.wikipedia.org/wiki/Context_switch。简单说就是将一个用户线程的状态保存到内存恢复另一个用户线程的状态并且更新调度程序的数据结构导致上下文切换比较慢。 2、go语言使用了所谓的N:M调度的技术实现了自己的调度器它在N个系统线程上多路复用或调度M个协程也就是说由n个系统线程生成了m个go的协程可以这么理解吧。go语言的调度工作类似于系统内核的调度但是它只关注单个go程序的协程。 另外一点就是go的协程是没有标识的在java中当前执行的线程都会有一个唯一的标识它的好处就是可以很容易的就构建出一个抽像的thread-local storage即java中的ThreadLocal每个线程都可以创建出这样一个数据结构存储只属于当前线程的一些变量。但是goroutine并不支持因为ThreadLocal可能会被滥用。go语言提倡的是一种更简单的编程方式即参数影响函数的行为应该是显性的。 
go因为在创建协程的数量上一般没有特别的限制所以可以很轻松的创建出很多个协程出来而java因为采用的是1:1的线程模型线程数量特别是并发线程数会受到CPU和操作系统的限制我记得java线程池会获取当前可使用的CPU核数可能有误所以并发性能上应该不如go语言有人也说go语言天生就带有高并发光环加持。这里无意区分java和go孰优孰劣只是想从线程和协程的实现上来简单的了解下二者的差别。 作者非典型_程序员 链接https://www.jianshu.com/p/6168b10dee34 来源简书 著作权归作者所有。商业转载请联系作者获得授权非商业转载请注明出处。 
java线程和go协程 - 简书