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 ...
随机推荐
- wpf treeview 数据绑定 递归绑定节点
1.先上效果 将所有节点加入ComboBox数据源,在ComboBox中选择时下方Treeview显示该节点下的子节点. 1.xaml文件,将以下代码加入界面合适位置 <StackPanel&g ...
- Mysql 导入文件提示 --secure-file-priv option 问题
MYSQL导入数据出现:The MySQL server is running with the --secure-file-priv option so it cannot execute this ...
- 基于Zookeeper实现多进程分布式锁
一.zookeeper简介及基本操作 Zookeeper 并不是用来专门存储数据的,它的作用主要是用来维护和监控你存储的数据的状态变化.当对目录节点监控状态打开时,一旦目录节点的状态发生变化,Watc ...
- 关于linux系统CPU篇--->CPU使用率升高
1.CPU使用率为单位时间内CPU使用情况的统计,以百分比的方式展示. LINUX作为一个多任务操作系统,将每个CPU的时间划分为很短的时间片,再通过调度器轮流分配给各个任务使用,因此造成多任务同时运 ...
- Maven Webapp项目web.xml版本记录
web.xml 2.0版本 <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3// ...
- 02:安装 Kerberos
1.1 环境介绍 参考博客:https://www.cnblogs.com/xiaodf/p/5968178.html https://www.douban.com/note/701660289/ ...
- 14: InfluxDB+Grafana打造大数据监控利器
参考博客: https://www.cnblogs.com/davidwang456/p/7795263.html
- JAVA随笔----浅谈lombok注解
在Java开发中,注解可谓是帮了大忙.注解的使用帮助我们简化了代码,让代码更加简洁.今天就来谈谈常用的Lombok注解. lombok注解文档 lombok官方下载地址 先看一下lombok支持的一些 ...
- day15
三元表达式 符合python语法的表达方式(形式,公式)称之为表达式 三元:三个元素 总体就是,由三个元素组成表达式其目的是为了简化书写,既然是简化必然有局限性三元表达式只能帮你简化仅有两个分支的if ...
- Oracle使用——数据泵导入导出数据库——impdp/expdp使用
使用前提 EXPDP和IMPDP只可以在Oracle服务端使用. EXP导出的文件只可以使用IMP导入,不适用于IMPDP导入文件:EXPDP导出的文件只可以使用IMPDP导入,而不适用于IMP导出文 ...