go语言和java并发_彻底搞清楚Java并发 (一) 基础
多线程编程是为了让程序运行得更快,但是不是说,线程创建地越多越好,线程切换的时候上下文切换,以及受限于硬件和软件资源的限制问题
上下文切换
单核CPU同样支持多线程编程,CPU通过给每个线程分配CPU时间片来实现这个机制,时间片是CPU分配给各个线程的时间,这个时间片非常短,所以就不得不通过切换线程来执行(时间片一般是几十毫秒)
当前任务执行一个时间片后,会切换到下一个任务,但是,在切换前会保存上一个任务的状态,这样的话下次这条线程获取到时间片之后就可以恢复这个任务的状态
协程
协程说通俗一点就是由线程调度的线程,操作系统创建一个进程,进程再创建若干个线程并行,线程的切换由操作系统负责调度,Java语言等线程其实与操作系统线程是1:1的关系,每个线程都有自己的Stack,Java在64位操作系统默默人stack大小为1024kb,所以一个进程也是不能够开启上万个线程的
基于J2EE项目都是基于每个请求占用一个线程去完成完整的业务逻辑,(包括事务)。所以系统的吞吐能力取决于每个线程的操作耗时。如果遇到很耗时的I/O行为,则整个系统的吞吐立刻下降,比如JDBC是同步阻塞的,这也是为什么很多人都说数据库是瓶颈的原因。这里的耗时其实是让CPU一直在等待I/O返回,说白了线程根本没有利用CPU去做运算,而是处于空转状态。
Java的JDK里有封装很好的ThreadPool,可以用来管理大量的线程生命周期,但是本质上还是不能很好的解决线程数量的问题,以及线程空转占用CPU资源的问题。
先阶段行业里的比较流行的解决方案之一就是单线程加上异步回调。其代表派是node.js以及Java里的新秀Vert.x。他们的核心思想是一样的,遇到需要进行I/O操作的地方,就直接让出CPU资源,然后注册一个回调函数,其他逻辑则继续往下走,I/O结束后带着结果向事件队列里插入执行结果,然后由事件调度器调度回调函数,传入结果。
协程的本质上其实还是和上面的方法一样,只不过他的核心点在于由他进行调度,遇到阻塞操作,立刻yield掉,并且记录当前栈上的数据,阻塞完后立刻再找一个线程恢复栈并把阻塞的结果放到这个线程上去跑,这样看上去好像跟写同步代码没有任何差别,这整个流程可以称为coroutine,而跑在由coroutine负责调度的线程称为Fiber。比如Golang里的 go关键字其实就是负责开启一个Fiber,让func逻辑跑在上面。而这一切都是发生的用户态上,没有发生在内核态上,也就是说没有切换上下文的开销。
Java线程调度
JVM必须维护一个有优先权,基于优先级的调度模式,优先级的值很重要,因为Java虚拟机和下层的操作系统之间的约定是操作系统必须选择有最高优先权的Java线程运行,所以我们说Java实现了一个基于优先权的调度程序该调度程序使用一种有优先权的方式实现,这意味着当一个有更高优先权的线程到来时,无论低优先级的线程是否在运行,都会中断(抢占)它(JVM会这么做)。这个约定对于操作系统来说并不总是这样,这意味着操作系统有时可能会选择运行一个更低优先级的线程。
yield()方法
理论上,yield意味着放手,放弃,投降。一个调用yield()方法的线程告诉虚拟机它乐意让其他线程占用自己的位置。这表明该线程没有在做一些紧急的事情。注意,这仅是一个暗示,并不能保证不会产生任何影响。
/**
* A hint to the scheduler that the current thread is willing to yield its current use of a processor. The scheduler is free to ignore
* this hint. Yield is a heuristic attempt to improve relative progression between threads that would otherwise over-utilize a CPU.
* Its use should be combined with detailed profiling and benchmarking to ensure that it actually has the desired effect.
*/
public static native void yield();
Yield是一个静态的本地(native)方法
Yield告诉当前正在执行的线程把运行机会交给线程池中拥有相同优先级的线程。
Yield不能保证使得当前正在运行的线程迅速转换到可运行的状态
它仅能使一个线程从运行状态转到可运行状态,而不是等待或阻塞状态
join()方法
如果一个线程A执行了thread.join()方法目的是,当前线程A等待thread线程终止之后才从thread.join()返回,
/**
* Waits for this thread to die.
*
*
An invocation of this method behaves in exactly the same
* way as the invocation
*
*
* {@linkplain #join(long) join}{@code (0)}
*
*
* @throws InterruptedException
* if any thread has interrupted the current thread. The
* interrupted status of the current thread is
* cleared when this exception is thrown.
*/
public final void join() throws InterruptedException {
join(0);
}
/**
* Waits at most {@code millis} milliseconds for this thread to
* die. A timeout of {@code 0} means to wait forever.
*
*
This implementation uses a loop of {@code this.wait} calls
* conditioned on {@code this.isAlive}. As a thread terminates the
* {@code this.notifyAll} method is invoked. It is recommended that
* applications not use {@code wait}, {@code notify}, or
* {@code notifyAll} on {@code Thread} instances.
*
* @param millis
* the time to wait in milliseconds
*
* @throws IllegalArgumentException
* if the value of {@code millis} is negative
*
* @throws InterruptedException
* if any thread has interrupted the current thread. The
* interrupted status of the current thread is
* cleared when this exception is thrown.
*/
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
如何减少上下文切换
无锁并发编程,多线程竞争锁的时候,会引起上下文切换,如将数据的ID按照Hash算法取模分段,不同线程处理不同段的数据
CAS算法,Java的Atomic包下使用的同步类都是使用CAS和Volatile实现的无锁
线程数量的控制
协程:单线程内实现多任务的调度,在单线程中维持多个任务间的切换
如何避免死锁
避免一个线程同时获得多个锁
避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源
尝试使用定时锁,tryLock(time)代替内部锁的机制
对于数据库来说,加锁和解锁必须在同一条连接中,否则将会出现问题
go语言和java并发_彻底搞清楚Java并发 (一) 基础相关推荐
- java书籍_还搞不定Java多线程和并发编程面试题?你可能需要这一份书单!
点击蓝色"程序员书单"关注我哟 加个"星标",每天带你读好书! 在介绍本书单之前,我想先问一下各位读者,你们之前对于Java并发编程的了解有多少呢.经过了1 ...
- oracle java 并发_【转】JAVA并发教程(ORACLE官网资料)
本文是Oracle官方的Java并发相关的教程,感谢并发编程网的翻译和投递. 计算机的使用者一直以为他们的计算机可以同时做很多事情.他们认为当其他的应用程序在下载文件,管理打印队列或者缓冲音频的时候他 ...
- python 单例模式内存泄露_彻底搞懂Java内存泄露
之前一直在简书写作,第一次发布到SF上来,也是第一次使用SF,后面会尽量同步到SF,更多文章请关注: 简书 编程之乐 转载请注明出处:谢谢! Java内存回收方式 Java判断对象是否可以回收使用的而 ...
- 此安装程序必须使用 java 开发工具包 (jdk) 执行_彻底搞懂Java开发工具包(JDK)安装及环境变量配置...
[官方正版]java jdk 9学习笔记 78.4元 包邮 (需用券) 去购买 > 一.Java 和 JDK 是什么 Java:Java是一种优秀的程序设计语言,它有非常多的语言特性,如简单性. ...
- java项目中没有jdk包_彻底搞懂Java开发工具包(JDK)安装及环境变量配置
一.Java 和 JDK 是什么 Java:Java是一种优秀的程序设计语言,它有非常多的语言特性,如简单性.面向对象.可移植性等.Java 并不只是一种语言,而是一个完整的平台,它有一个庞大的库,其 ...
- mysql每秒支持多少并发_如何设计一个高并发系统?
面试题 如何设计一个高并发系统? 面试官心理分析 说实话,如果面试官问你这个题目,那么你必须要使出全身吃奶劲了.为啥?因为你没看到现在很多公司招聘的 JD 里都是说啥,有高并发就经验者优先. 如果你确 ...
- 【Java多线程】轻松搞定Java多线程(一)
轻松搞定Java多线程(一) Java多线程详解(一) 1. 线程简介 2.线程的创建 2.1 三种创建方式 2.2 Thread 2.3 实现Runnable 2.3.1 初识并发问题 2.3.2 ...
- python和c和java难度_浅谈:Java和C语言各自的学习难度
许多初学者在编程入门之前,都会在编程语言的选择上犹豫不决.一般来讲,Java和C语言是编程小白最青睐的两种编程语言.那么,Java和C语言哪个学习难度更大呢?虽然两者的区别挺大的,但是学习难度上并不能 ...
- 来电通java版_终于有人把Java程序员必学知识点整理出来了,令人有如醍醐灌顶...
JVM 无论什么级别的Java从业者,JVM都是进阶时必须迈过的坎.不管是工作还是面试中,JVM都是必考题.如果不懂JVM的话,薪酬会非常吃亏(近70%的面试者挂在JVM上了) 详细介绍了JVM有关于 ...
最新文章
- 张宏江对话清华“智班”:我想看到更多极客
- 【extjs6学习笔记】1.1 初始:创建项目
- 蓝牙4.0 vs 蓝牙4.1 vs 蓝牙4.2 vs 蓝牙5.0
- 全国计算机二级考试vf知识点总结,VF全国计算机等级考试二级公共基础知识点总结.doc...
- linux集群架构(一),集群概述、高可用配置
- 在这里的周末休息也就是看看奥运
- java redis 批量删除key_互联网大厂Java工程师面试指南——Redis篇
- Retina时代的前端视觉优化
- 牛客题霸 [ 实现二叉树先序,中序和后序遍历]C++题解/答案
- 前端学习(1525):简化模板代码
- python批量将pdf转成word_如何用Python把pdf转换成word
- 抓到的一次suse11 xen用libvirt连接的错误
- 中国金融出版社出版的2016版《综合》
- 短视频如何有效涨粉?三个小技巧来帮忙,吸粉引流也不难
- 控制系统中对信号求导的注意事项
- 【万人围观】20位著名作家,100句惊艳了时光的名句
- 计算机组成原理区分正负数实验,计算机组成原理实验报告(4个).doc
- ArduPilot 开发手册学习:写在前面
- 关于iOS的自动弹出键盘问题
- HTML春节贺卡,HTML5+CSS3实现春节贺卡