Java并发编程相关知识整理
1、什么是进程、线程、多线程?
进程当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源。进程间通讯依靠IPC资源,例如管道、套接字
线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码是共享的,即不同的线程可以执行同样的函数。
多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说说允许单个程序创建多个并行执行的线程来完成各自的任务。线程间通讯依靠JVM提供的API,例如wait()、notify、notifyAll等方法,线程间还可以通过共享的主内存来进行值的传递
2、多线程的优缺点?
优点:可以提高CPU的利用率。在多线程程序中,一个线程必须等待的时候,CPU可以运行其他的线程而不是等待,提高程序相应效率。
缺点:线程也是程序,所有线程需要占用内存,线程越多占用的内存也越多。
线程需要协调和管理,所以需要CPU时间跟踪线程
线程之间对共享资源的访问会互相影响,必须要解决竞用共享资源的问题
线程太多会导致控制太复杂,最终可能造成很多Bug
3、多线程一定比单线程快吗?
不一定,由于多线程会存在线程上下文切换,会导致程序执行速度变慢,但可以充分利用CPU,所以对于用户来说,可以减少用户响应时间。
比如,尝试使用并行和串行分别执行累加的操作观察是否并行执行一定比串行更快:
package com.test.demo; public class Tester { private static final long count = 1000000000; public static void bingxing() throws Exception {
long startTime = System.currentTimeMillis(); //通过匿名内部类来创建线程
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
int a = 0;
for(long i = 0; i < count; i++) {
a += 1;
}
}
}); Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
int b = 0;
for(long k = 0;k < count; k++) {
b+=1;
}
}
}); //启动线程
thread1.start();
thread2.start(); //等待线程结束
thread1.join();
thread2.join(); long time = System.currentTimeMillis() - startTime ;
System.out.println("并行花费时长:" + time + "ms");
} public static void chuanxing() {
long startTime = System.currentTimeMillis();
int a = 0;
for(long i = 0; i < count; i++) {
a += i;
}
int b = 0;
for(long k = 0;k < count; k++) {
b+=k;
}
long time = System.currentTimeMillis() - startTime ;
System.out.println("串行花费时长:" + time + "ms");
} public static void main(String[] args) throws Exception {
bingxing();
chuanxing();
} }
循环次数 | 串行执行/ms | 并行执行/ms | 结果 |
1千 | 0ms | 2ms | 慢 |
1万 | 0ms | 2ms | 慢 |
10万 | 3ms | 4ms | 慢 |
100万 | 6ms | 4ms | 快 |
1000万 | 13ms | 11ms | 快 |
1亿 | 89ms | 78ms | 快 |
从测试结果看出当超过100万次循环后,并行执行的优势越加明显,不超过100万次循环时,串行执行的速率要比并行执行的速率高,原因就是多线程有上下文切换的开销。
4、阻塞与非阻塞
阻塞和非阻塞通常用来形容多线程之间的相互影响
阻塞是指一个线程占用了临界区资源,那么其他所有需要这个资源的线程就不洗在这个临界区中进行等待,等待会导致线程挂起,这种情况就是阻塞
非阻塞强调没有一个线程可以妨碍其他线程执行,所有线程都会尝试不断向前执行
5、临界区
临界区用来表示一种公共资源或者共享资源可以被多个线程使用,但是每一次只能有一个线程使用它,一旦临界区资源被占用,其他线程想要使用这个资源,就必须等待
6、死锁Deadlock、饥饿starvation、活锁Livelock
死锁表示两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们将无法推进下去,此时称系统处于死锁状态,这些永远在互相等待的进程成为死锁进程
饥饿表示一个或者多个线程应为种种原因无法获得所需要的资源,导致一直无法执行。导致饥饿的原因可能是该线程优先级太低,而高优先级的线程不但抢占它所需要的资源,导致其无法向前推进,另外一种可能是,某线程一直占着关键资源不放,导致其他需要这个资源的线程无法正常执行
活锁表示两个或者多个线程主动将资源释放给其他线程,导致没有一个线程可以同时拿到所有资源而正常执行。
7、如何避免死锁
指定获取锁的顺序
8、sleep()与wait()区别
sleep()是Thread类的静态方法,使当前线程睡眠n毫秒,线程进入阻塞状态。当睡眠时间到了,解除阻塞,进行可运行状态,等待CPU的到来。睡眠不释放锁。
wait()是Object的方法,必须和synchronized关键字一起使用,线程进入阻塞状态,当notify或者notifyall被调用后,会解除阻塞。但是,只有重新占用互斥锁之后才会进入可运行状态。睡眠时,释放互斥锁。
9、synchronized关键字底层实现
进入时,执行monitorenter,将计数器+1,释放锁monitorexit时,计数器-1;当一个线程判断到计数器为0时,则当前锁空闲,可以占用,反之,当前线程进入等待状态。
10、volatile关键字功能
直接与主内存产生交互,进去读写操作,保证可见性;禁止JVM进行指令重排序;能使一个非原子操作变为原子操作。比如对一个volatile型的long或者douuble变量的读写是原子
11、ThreadLocal关键字
当使用ThreadLocal维护变量时,其为每一个使用该变量的线程提供独立的变量副本,所以当每一个线程都可以独立的改变自己的副本,而不会影响其他线程对应的副本
12、线程池的了解
java.util.concurrent.ThreadPoolExcutor类就是一个线程池。客户端调用ThreadPoolExecutor.submit(Runable Task)提交任务,线程池内部维护的工作者线程的数量就是该线程池的线程池大小。
当前线程池大小:表示线程池中实际工作者线程的数量
最大线程池大小:表示线程池张允许纯在的工作者线程的数量上限
核心线程大小:表示一个不大于最大线程池大小的工作者线程数量上限
线程池有三种状态:
①、如果运行的线程小于核心线程大小,则Executor始终首选添加新的线程,而不进行排队
②、如果运行的线程等于或者多于核心线程大小,则Executor始终首选将请求加入队列,而不是添加新线程;
③、如果无法将请求加入队列,即队列已经满了,则创建新的线程,除非创建此线程超过最大线程池大小,在这种情况下,任务将会被拒绝
13、线程池的作用
减少创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务
可以根据系统的承受能力,调整线程中工作线程的数目,防止因为消耗过多的内存,而把服务器过载
14、创建线程的实现方式
继承Thread类,实现Runable接口,实现Callable接口
15、run()方法和start()方法的区别
start()方法会新建一个线程并让这个线程执行run()方法;而直接调用run()方法只是作为一个普通的方法调用而已,它只是会在当前线程中,串行执行run()中的代码
Java并发编程相关知识整理的更多相关文章
- Java并发编程核心知识体系精讲
第1章 开宗明义[不看错过一个亿]本章一连串设问:为什么学并发编程?学并发编程痛点?谁适合学习本课?本课程包含内容和亮点?首先4大个理由告诉你为什么要学,其实源于JD岗位要求就不得不服了.其次5个痛点 ...
- Java 并发编程小册整理好了
Java 有并发,并发知识之大,一口吃不下 这曾是我不愿意触碰的知识角 多次一头扎进并发,无功而返 为应对面试,临时苦苦记忆,不成体系 这一次我决定从基础开始,攻克它 12,0000 字 68Mb 高 ...
- 多线程(一)java并发编程基础知识
线程的应用 如何应用多线程 在 Java 中,有多种方式来实现多线程.继承 Thread 类.实现 Runnable 接口.使用 ExecutorService.Callable.Future 实现带 ...
- Java虚拟机JVM相关知识整理
Java虚拟机JVM的作用: Java源文件(.java)通过编译器编译成.class文件,.class文件通过JVM中的解释器解释成特定机器上的机器代码,从而实现Java语言的跨平台. JVM的体系 ...
- Java 网络编程相关知识
网络的一些基础知识 IP地址分类 IP地址根据网络ID的不同分为5种类型,A类地址.B类地址.C类地址.D类地址和E类地址.A类保留给政府机构,B类分配给中等规模的公司,C类分配给任何需要的人,D类用 ...
- Java集合框架相关知识整理
1.常见的集合有哪些? Collection接口和Map接口是所有集合框架的父接口 Collection接口的子接口包括:Set接口和List接口 Map接口的实现类主要有:HashMap ...
- Java并发编程学习前期知识下篇
Java并发编程学习前期知识下篇 通过上一篇<Java并发编程学习前期知识上篇>我们知道了在Java并发中的可见性是什么?volatile的定义以及JMM的定义.我们先来看看几个大厂真实的 ...
- Java工程师学习指南第4部分:Java并发编程指南
本文整理了微信公众号[Java技术江湖]发表和转载过的Java并发编程相关优质文章,想看到更多Java技术文章,就赶紧关注本公众号吧吧. [纯干货]Java 并发进阶常见面试题总结 [Java基本功] ...
- java并发编程--Runnable Callable及Future
1.Runnable Runnable是个接口,使用很简单: 1. 实现该接口并重写run方法 2. 利用该类的对象创建线程 3. 线程启动时就会自动调用该对象的run方法 通常在开发中结合Execu ...
随机推荐
- vue知识总结
vue: 渐进式JavaScript 框架 Vue项目构建 npm install -g vue vue init webpack-simple my-project cd my-project np ...
- getparameter的使用
在做项目的过程中,会遇到跳转的页面,直接打开到里面的子项,这个时候,看了UI给我设计了四个页面,如果做四个页面,肯定是可以实现的.但是这个不符合前端的设计.就在想通过点击传值进去,肯定是能够获取到的. ...
- 20175208《Java程序设计》第五周学习总结
教材学习内容总结 1.接口:1)接口声明: interface //接口的名字 2)接口体2.实现接口:类实现接口:一个类需要在类声明中使用关键字implements声明该类实现一个或多个接口.如果实 ...
- JavaScript笔记1———js的数据类型
JS的数据类型有: 1.数值类型(Number):js中所有数字均用浮点数字表示. 可以表示32位(即4字节)的整数,也可以表示64位(即8字节)的浮点数(小数). 也可以用二进制.八进制.十进制.十 ...
- Node.js基础学习三之登录功能
本篇介绍Node.js访问数据库并返回数据给客户端 需求基于Node.js学习(二) 数据库请下载:user.sql 1.创建user 实体类(model-user.js) function User ...
- JavaScript数组对象常用方法
JavaScript数组对象常用方法 方法 形式 返回值 是否改变原数组 描述 concat -items: ConcatArray[] 追加之后的数组 否 连接两个或更多的数组,并返回结果.注意 c ...
- Gatling实战(三)
无论是性能测试还是自动化测试,有一个很重要的点就是变量(参数化),因为真实环境是很少同时产生并发很高而且所有参数都一模一样的请求的,就算有这样的接口,开发肯定用缓存来挡了,这种一般不会是瓶颈,真正瓶颈 ...
- 富文本编辑器Quill(一)简单介绍
Quill是一个很流行的富文本编辑器,github上star大约21k: github:https://github.com/quilljs/quill/ 官网: https://quilljs.co ...
- FL Studio中音频ASIO4ALL的设置
上期我们讲解了FL Studio中音频的相关设置,今天我们来进一步讲解音频设置中的ASIO4ALL的设置,FL Studio安装包括FL Studio ASIO和第三方ASIO驱动程序ASIO4ALL ...
- SQL Server同一表不同列数据同步
直接上脚本 update table set a=b where a=xxx table==表名称 a==需要同步的列 b==数据源列,就是a列要的数据是b列的数据 where 条件.不加where则 ...