JVM与线程

JVM目录

  • JVM与线程
    • JVM
      • 1.JVM内存结构及每部分的作用
      • 2.JVM中那些部分出现内存溢出
      • 3.方法区, 永久化, 元空间的区别
      • 4.常见JVM内存参数
      • 5.什么是垃圾对象
      • 6.垃圾回收算法
      • 7.简述gc分代回收
      • 8.什么是三色标记法
      • 9.并发标记会带来什么问题
      • 10.并发标记解决方案
      • 11.jdk 8 的类加载器有哪些
      • 12.常见的垃圾回收器
      • 13.四种引用和回收时机
    • 线程
      • 1.线程和进程有什么区别?
      • 2.并发和并行有什么区别?
      • 3.线程创建4种方式?
      • 4.线程有哪些状态
      • 5.为什么要使用线程池?
      • 6.线程池的构造方法里几个参数的作用分别都是什么?
      • 7.线程池流程
      • 8.线程池拒绝策略有哪些
      • 9.notify()和 notifyAll()有什么区别?
      • 10.wait()和sleep()的区别
      • 11.volatile能否保证线程安全
      • 12.lock锁和synchronized锁区别
      • 13.悲观锁和乐观锁区别
      • 14.什么是cas
      • 15.HashTable的默认初始容量是多少,扩容因子是多少?每次扩容多少?
      • 16.HashTable在计算索引的时候,为什么不进行二次hash
      • 17.ConcurrentHashMap的initcapacity和loadFactor与HashMap的含义相同吗?
      • 18.ConcurrentHashMap相关问题?
      • 19.ThreadLocal
      • 20.@Async注解失效的

JVM


1.JVM内存结构及每部分的作用

JVM可以分为3大部分:类加载器,运行时数据区和执行引擎
方法区:存于存放加载到JVM内存中的类的源信息
堆:创建出来的对象
程序计数器:线程进行上下文切换,记录下次指令执行的位置
java虚拟机栈: java方法调用使用的内存(栈帧)
本地方法栈:native方法调用使用的内存;
堆和方法区:所有线程共享
程序计数器和栈内存:所有线程独享,每个线程都有自己的程序计数器和虚拟机栈


2.JVM中那些部分出现内存溢出

不会出现存在溢出的区域-程序计数器
OutOfMemoryError:
堆内存耗尽-对象越拉越多, 又一直在使用,不能被垃圾回收;
方法区内存耗尽-加载的类越来越多, 很多框架都会在运行期间动态产生新的类;
虚拟机栈累积-每个线程最多会占用1M内存, 线程个数越来越多, 而又长时间运行不销毁时;
StackOverflowError:
JVM虚拟机栈, 原因有方法递归为正确结束, 序列化json时循环引用;
每个虚拟机栈默认1M;


3.方法区, 永久化, 元空间的区别

①方法区:
JVM规范中定义的一块内存区域, 用来储存类元数据, 方法字节码等;
永久化: Hostpot虚拟机对JVM规范1.8以前实现
元空间: Hostpot虚拟机对JVM规范1.8以后实现
②元空间储存什么
当一个类被加载到内存以后, 类的源信息储存在元空间;
在堆内存会产生对象Class对象可以找到类的源信息. java程序无法直接访问元空间;
③元空间的类的源信息什么时候卸载:
当类在堆内存的Class, 对象都被gc回收, 类加载器对象也被回收


4.常见JVM内存参数

堆内存大小:
-Xms:初始堆内存(包括新生代和老年代)
-Xmx:最大堆内存(包括新生代和老年代)
通常建议将-Xms与-Xmx设置为大小相等, 即不惜要保留内存, 不需要从小到大增长, 这样性能较好
默认情况下: 新生代和老年代比例1:2 -XX:NewRatio=2:1
默认情况下:新生代中eden与form及to的比例8:1:1 -XX:survivorRatio=8:1
设置新生代大小:
-Xmn 新生代大小
-XX:NewSize 初始新生代大小
-XX:MaxNewSize 最大新生代大小
设置栈内存大小: -Xss
元空间内存设置:
默认无上限
-XX:MaxMetaspaceSize: 最大元空间


5.什么是垃圾对象

①可达性分析算法:
将"GC Roots"作为起点,从这些引用向下搜索指向的对象,能找到的对象就标记为非垃圾对象,找不到的对象就标记为垃圾对象。
JVM虚拟机栈中的引用类型变量
本地方法栈:引用类型变量
方法区:使用static | final修饰的引用类型变量
②引用计数器法


6.垃圾回收算法

找到垃圾对象后如何清理垃圾对象
①标记清除算法
通过可达性分析算法找到堆内存中不是垃圾的对象,进行标记;
将没有标记到的对象回收;
缺点:内存碎片太严重(可用的内存空间不连续),将来如果要存放一个比较大的对象,可能无法存储
②标记整理算法
通过可达性分析算法找到堆内存中不是垃圾的对象,进行标记;
将没有标记到的对象回收;
对内存进行整理;
缺点:是性能上较慢;
③标记复制法
将整个内存分成两个大小相等的区域,from 和 to,其中 to 总是处于空闲,from 存储新创建的对象;
标记阶段与前面的算法类似;
在找出存活对象后,会将它们从 from 复制到 to 区域,复制的过程中自然完成了碎片整理;
复制完成后,交换 from 和 to 的位置即可;
缺点:是会占用成倍的空间;


7.简述gc分代回收

伊甸园 eden,最初对象都分配到这里,与幸存区 survivor(分成 from 和 to)合称新生代;

当伊甸园内存不足,标记伊甸园与 from(现阶段没有)的存活对象;

将存活对象采用复制算法复制到 to 中,复制完毕后,伊甸园和 from 内存都得到释放;

将 from 和 to 交换位置;

经过一段时间后伊甸园的内存又出现不足;

标记伊甸园与 from(现阶段没有)的存活对象;

将存活对象采用复制算法复制到 to 中;
复制完毕后,伊甸园和 from 内存都得到释放;

将 from 和 to 交换位置;

当幸存区对象熬过几次回收(最多15次),晋升到老年代(幸存区内存不足或大对象会导致提前晋升)


8.什么是三色标记法

垃圾回收器标记存活对象的一种方式
1.从GC Root开始,在引用链上的对象先标记为灰色

2.如果该对象没有属性指向其他对象,或者指向的对象已经全部标记成了灰色,标记成黑色

4.最终黑色对象就是存活对象


9.并发标记会带来什么问题

如果标记的线程和用户线程同时执行,会引发2个问题;
用户线程有可能会修改对象之间的引用关系;
浮动垃圾:

并发漏标(严重):

黑色对象指向一个白色对象;
黑色对象指向了一个添加的白色;


10.并发标记解决方案

增量更新:只要赋值产生,被赋值的对象会被记录下来
原始快照:新添加的对象会被记录下来, 引用关系发生变化的对象会被记录下来


11.jdk 8 的类加载器有哪些


所谓的双亲委派,就是指优先委派上级类加载器进行加载,如果上级类加载器;
能找到这个类,由上级加载,加载后该类也对下级加载器可见;
找不到这个类,则下级类加载器才有资格执行加载;


12.常见的垃圾回收器

1.垃圾回收器的分类
①按照线程数划分
单线程:垃圾回收线程只有一个
多线程:垃圾回收线程有多个
②工作模式
独占式:垃圾回收线程在执行的过程中,工作线程暂停
并发式:垃圾回收线程和工作线程可以并发执行
③内存碎片的整理方式
压缩式:标记整理算法
非压缩式:标记清除算法
④工作区域
新生代
老年代
2.GC的性能指标
①吞吐量
用户线程执行的时长/总时长
总时长=用户线程执行的时长 + 垃圾回收线程执行的时长
eg:JVM总共运行了100分钟,1分钟进行垃圾回收99分钟运行用户线程,吞吐量就是99%
②暂停时间
垃圾回收线程每次工作占用的时间
③收集频率
相对于用户线程,垃圾回收线程执行的频率
④收集频率 暂停时间 吞吐量关系
吞吐量和收集频率,暂停时间矛盾
3.垃圾回收器与分代的关系
堆内存分为新生代和老年代,并不是所有的垃圾回收器都可以回收整个堆内存;
有些垃圾回收器是回收新生代。
有些垃圾回收器是回收老年代。
新生代的垃圾回收器:Serial GC ParallelScavenge GC ParNew GC
老年代的垃圾回收器:Serial Old GC Parallel Old GC CMS
整堆回收的垃圾回收器: G1
4.垃圾回收器的组合关系
不是所有的新生代的垃圾回收器都可以配置所有老年代的垃圾回收器
虚线的部分表示,在新版本的JDK中已经不支持搭配关系,在老版本的JDK中支持。
Serial / Serial Old GC
ParNew/CMS
Parallel Scavenge / Parallel Old
5.如何查看进程中使用的GC
-XX:+PrintCommandLineFlags
6.每一种垃圾回收器的特点
①Serial SerialOld
1.单线程的垃圾回收器
2.会产生Stop The Word STW(垃圾回收线程运行的时候,用户线程暂停)
3.简单高效
4.新生代采用标记复制算法,老年代采用标记整理
5.在jdk5之前Serial GC可以配置CMS使用,并且让Serial Old作为后备
②ParNew
1.ParNew收集器是Serial 收集器的多线程版本
2.在垃圾回收的时候,采用多个线程一起回收
3.采用的收集算法和Serial一样
4.是新版本中唯一和CMS组合使用的
③Parallel Scavenge Parallel Old
1.新生代采用标记复制,老年代采用标记整理
2.他的关注度是吞吐量
④CMS垃圾回收器
1.关注的是最短暂停时间,比较注重用户体验
2.他是HotSpot真正意义上的一款并行并发式垃圾回收器
3.基于标记清除算法实现
4.运行过程比前面几种复杂
初始标记:
暂停所有用户线程,通过可达性分析算法,标记存活对象,时间很短
并发标记:
开启用户线程,并发标记可达对象(不能保证标记所有可达对象),因为用户线程有可以更新了引用。根据记录引用发生变化的地方
重新标记:
暂停所有用户线程,进行重写标记,修正并发标记阶段,用户线程运行到这引用变动的对象
并发清理
开启用户线程,同时GC线程对未标记的区域进行清除
5.缺点
无法清除浮动垃圾
采用并发-清除会产生内存碎片
⑤G1
1.他将堆内存划分为大小相等的多个Region(区域)
2.一般一个Reign大小等于堆内存大小/2048
3.保留新生代,老年代这些概念
4.每个Region的区域功能可能会产生变化。
5.G1中有专门存储大对象(一个对象超过Region的50%)的区域Humongous
回收过程


13.四种引用和回收时机

①强引用
----A a = new A();
----通过 GC Root 的引用链,如果引用不到该对象,该对象才能被回收
②软引用(SoftReference)
----SoftReference a = new SoftReference(new A());
----a---->软引用对象---->对象
a-------->软引用对象是强引用
软引用对象---->对象是软引用
----如果仅有软引用该对象时,首次垃圾回收不会回收该对象,如果内存仍不足,再次回收时才会释放对象
----软引用自身需要配合引用队列来释放
③弱引用(WeakReference)
----WeakReference a = new WeakReference(new A());
----a---->弱引用对象---->对象
a-------->软引用对象是强引用
弱引用对象---->对象是弱引用
----只要发生垃圾回收,就会释放该对象
----弱引用自身需要配合引用队列来释放
④虚引用(PhantomReference)
----PhantomReference a = new PhantomReference(new A(), referenceQueue);
----如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。



线程


1.线程和进程有什么区别?

进程:程序由指令和数据组成,但这些指令要运行,数据要读写,就必须将指令加载至 CPU,数据加载至内存。在指令运行过程中还需要用到磁盘、网络等设备。进程就是用来加载指令、管理内存、管理 IO 的
当一个程序被运行,从磁盘加载这个程序的代码至内存,这时就开启了一个进程。
进程就可以视为程序的一个实例。大部分程序可以同时运行多个实例进程(例如记事本、画图、浏览器等),也有的程序只能启动一个实例进程(例如网易云音乐、360 安全卫士等)
线程:一个进程之内可以分为一到多个线程。一个线程就是一个指令流,将指令流中的一条条指令以一定的顺序交给 CPU 执行

2.并发和并行有什么区别?

并发(concurrent)是同一时间应对多件事情的能力单核 cpu 下,线程实际还是 串行执行 的。操作系统中有一个组件叫做任务调度器,将 cpu 的时间片(windows下时间片最小约为 15 毫秒)分给不同的程序使用,只是由于 cpu 在线程间(时间片很短)的切换非常快,人类感觉是 同时运行的 。总结为一句话就是: 微观串行,宏观并行 ,一般会将这种 线程轮流使用 CPU 的做法称为并发, concurrent
并行(parallel)是同一时间动手做多件事情的能力多核 cpu下,每个 核(core) 都可以调度运行线程,这时候线程可以是并行的。

3.线程创建4种方式?

方法一,直接使用 Thread// 创建线程对象
Thread t = new Thread() {public void run() {// 要执行的任务}
};
// 启动线程
t.start();方法二,使用 Runnable 配合 ThreadRunnable runnable = new Runnable() {public void run(){// 要执行的任务}
};
// 创建线程对象
Thread t = new Thread( runnable );
// 启动线程
t.start();方法三,FutureTask 配合 Thread// 创建任务对象
FutureTask<Integer> task3 = new FutureTask<>(() -> {log.debug("hello");return 100;
});
// 参数1 是任务对象; 参数2 是线程名字,推荐
new Thread(task3, "t3").start();
// 主线程阻塞,同步等待 task 执行完毕的结果
Integer result = task3.get();
log.debug("结果是:{}", result);方法四,线程池

4.线程有哪些状态

站在JavaAPI的角度1.新建(NEW)new Thread()2.可运行状态(RUNABLE)调用start方法3.终结状态run方法中代码执行完毕新建--->可运行--->终结是不可逆4.阻塞状态没有获取锁的线程当获取锁的线程释放掉锁,重新抢占锁成功--->可运行状态5.等待状态获取锁的线程,调用锁对象.wait方法当其他线程调用锁对象.notify方法唤醒等待状态的线程,重新获取锁成功----->可运行状态6.有时限的等待获取锁的线程,调用锁对象.wait(long)方法当其他线程调用锁对象.notify方法唤醒等待状态的线程,重新获取锁成功----->可运行状态时间到了重新获取锁成功----->可运行状态调用线程的sleep(long)方法时间到了----->可运行状态

5.为什么要使用线程池?

1.减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
2.可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。


6.线程池的构造方法里几个参数的作用分别都是什么?

线程池就是管理线程的一个容器;
在java中线程池的实现
ThreadPoolExecutor构造方法中的7个参数

 corePoolSize 核心线程数目 - 池中会保留的最多线程数maximumPoolSize 最大线程数目 - 核心线程+救急线程的最大数目keepAliveTime 生存时间 - 救急线程的生存时间,生存时间内没有新任务,此线程资源会释放unit 时间单位 - 救急线程的生存时间单位,如秒、毫秒等workQueue - 工作队列,当没有空闲核心线程时,新来任务会加入到此队列排队,队列满会创建救急线程执行任务threadFactory 线程工厂 - 可以定制线程对象的创建,例如设置线程名字、是否是守护线程等handler 拒绝策略 - 当所有线程都在繁忙,workQueue 也放满时,会触发拒绝策略

7.线程池流程

1.当我们向线程池中添加任务
2.有核心线程执行任务如果核心线程都在执行任务将任务加入到任务队列等待核心线程执行完任务后,从队列中获取任务执行如果队列已经满了创建救急线程去救急线程执行任务救急线程执行完任务后,如果在keepAliveTime时间内没有任务执行,销毁如果救急线程也无法创建触发拒绝策略

8.线程池拒绝策略有哪些

抛异常 java.util.concurrent.ThreadPoolExecutor.AbortPolicy
由调用者执行任务 java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy
丢弃任务 java.util.concurrent.ThreadPoolExecutor.DiscardPolicy
丢弃最早排队任务,把新加任务添加到工作队列 java.util.concurrent.ThreadPoolExecutor.DiscardOldestPolicy

9.notify()和 notifyAll()有什么区别?

notify()唤醒锁对象等待区随机一个线程notifyAll()唤醒锁对象等待区的所有线程

10.wait()和sleep()的区别

相同点wait() ,wait(long) 和 sleep(long) 的效果都是让当前线程暂时放弃 CPU 的使用权,进入WAITING Time_Waiting 状态
不同点方法归属不同sleep(long) 是 Thread 的静态方法而 wait(),wait(long) 都是 Object 的成员方法,每个对象都有醒来时机不同执行 sleep(long) 和 wait(long) 的线程都会在等待相应毫秒后醒来wait(long) 和 wait() 还可以被 notify 唤醒,wait() 如果不唤醒就一直等下去它们都可以被打断唤醒锁特性不同wait 方法 必须基于锁对象调用,直接调用报错,而sleep没有限制wait 方法执行后会释放对象锁,允许其它线程获得该对象锁sleep 如果在 synchronized 代码块中执行,并不会释放对象锁

11.volatile能否保证线程安全

 不能可见性一个线程对共享变量进行了修改,另外一个线程能否看到修改后的结果有序性一个线程内代码是否按照编写顺序执行CUP有指令重排;要求:在单线程环境中如果执行结果是一样的;原子性一个线程内多行代码以一个整体运行,期间不能有其他线程的代码插队public class Test01 {private volitle static int a = 0;public static void main(String[] args) {for (int i = 1; i <= 10000; i++) {new Thread(() -> {a++;}).start();}while (Thread.activeCount() > 2) {Thread.yield();}System.out.println(a);}
}volatile能否保证线程安全保证可见性有序性(单例设计模式)

12.lock锁和synchronized锁区别

语法层面synchronized 是关键字底层是通过c++代码实现锁(monitor)synchronized同步代码块执行完毕会自动释放锁lock是一个接口用 java 语言实现需要手动调用 unlock 方法释放锁
功能层面具备基本的互斥、同步、锁重入功能互斥同步重入Lock 提供了许多 synchronized 不具备的功能获取阻塞状态的线程公平锁可超时tryLock多条件变量Condition condition = lock.newCondition();可以利用条件变量进行await();将线程加入等待队列可以利用条件变量进行condition.signal();唤醒等待队列某个线程可以利用条件变量进行condition.signalAll();唤醒等待队列某个线程Lock 有适合不同场景的实现

13.悲观锁和乐观锁区别

悲观锁悲观锁的核心代表是synchronized Lock思想1.只有获取锁的线程才能操作共享变量,每次只有一个线程能获取锁成功,获取锁失败的线程都要进入阻塞队列等待;2.线程从可运行到阻塞,再从阻塞到可运行,涉及到上下文切换,如果频繁发生会影响效率3.synchronized和Lock在获取锁的时候,如果锁已经被其他线程占用,还会重试几次
乐观锁乐观锁的代表是AtomicInteger,使用cas保证原子性思想1.每次只有一个线程能修改成功共享变量,其他修改失败的线程不需要阻塞,不断重试直到成功2.由于所有的线程一直运行,不需要阻塞,不牵扯频繁上下文切换3.需要多核cup的支持 cup>线程数量

14.什么是cas

 compare and switch(比较并交换)作用:可以保证对共享变量的操作是原子性原理:操作共享变量之前,先查看该共享变量是否进行了修改,如果进行了修改,重试;如果没有进行修改;修改共享变量代码public class Test01 {private static Unsafe unsafe;static {//Unsafe:cas的核心类try {Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");theUnsafe.setAccessible(true);unsafe = (Unsafe) theUnsafe.get(Unsafe.class);} catch (Exception e) {e.printStackTrace();}}public static void main(String[] args) throws Exception {//通过cas原子性操作int类型的一个方法Account account = new Account();Field balance = Account.class.getDeclaredField("balance");long offset = unsafe.objectFieldOffset(balance);while (true) {int current = account.balance;int change = current + 5;boolean b = unsafe.compareAndSwapInt(account, offset, current, change);if(b) {break;}}System.out.println(account.balance);}}class Account {public volatile int balance = 10;
}

15.HashTable的默认初始容量是多少,扩容因子是多少?每次扩容多少?

     /*** Constructs a new, empty hashtable with a default initial capacity (11)* and load factor (0.75).*/public Hashtable() {this(11, 0.75f);}int oldCapacity = table.length;
Entry<?,?>[] oldMap = table;
int newCapacity = (oldCapacity << 1) + 1;

16.HashTable在计算索引的时候,为什么不进行二次hash

 int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;(hash & 0x7FFFFFFF) ?hashtable默认容量是11,是一个质数(素数);扩容后也是质数,如果是质数取模的分散性本身就比较好;计算出来的索引分散性比较好public class Test05 {public static void main(String[] args) {//模拟存入hashtable中数据的keyInteger[] keys = {1189740546,1154154496,1137901570,1652097026,557842434,1236598786,2013724674,792657922,1078591488,1398276098};/*    for (Integer key : keys) {int hashCode = key.hashCode(); //Integer类型的数据,hashCode就是他包装的int值System.out.println(hashCode % 16);}*/for (Integer key : keys) {int hashCode = key.hashCode(); //Integer类型的数据,hashCode就是他包装的int值System.out.println(hashCode % 11);}}
}

17.ConcurrentHashMap的initcapacity和loadFactor与HashMap的含义相同吗?

 HashMap中initcapacity是数组的初始容量,loadFactor是扩容因子
当HashMap中元素的数量>initcapacity * loadFactor,数组会扩容一倍1.8 ConcurrentHashMap的initcapacity是预计在ConcurrentHashMap中存储的元素个数,数组的长度由ConcurrentHashMap来计算,结果是2的N次幂如何计算eg:initcapacity是6   loadFactor是0.5分配的数组多大2的n次幂 * 0.5 >6下次什么时候扩容初次分配数组大小,参考loadFactor,以后就不再参考loadFactor,统一参考0.7524

18.ConcurrentHashMap相关问题?

 1.7和1.8的区别get方法需要加锁吗?迭代的时候采用的是强一致性还是最终一致性使用synchronized替换ReentrentLock1.7和1.8的并发度ConcurrentHashMap相比Hashtable的并发度

19.ThreadLocal

 谈谈您对ThreadLocal的理解ThreadLocal可以实现对象的线程隔离,让每一个线程各用个的资源对象,避免争用实现的线程安全这种方案可以采用方法内的局部变量实现;局部变量也可以保证线程安全局部变量是无法在多个方法直接共享的ThreadLocal可以在一个线程内进行资源共享在一个线程的多个方法中实现共享资源对象ThreadLocal的原理每一个线程都有一个成员变量,类型是ThreadLocalMap,用来存储资源对象当调用ThreadLocal的set方法的时候,就是将ThreadLocal作为Key,将资源对象作为value存储到当前线程的ThreadLocalMap属性中当调用ThreadLocal的get方法的时候,就是将ThreadLocal作为Key,从当前线程的ThreadLocalMap属性中获取资源对象当调用ThreadLocal的remove方法的时候,就是将ThreadLocal作为Key,从当前线程的ThreadLocalMap属性中删除资源对象对资源进行线程隔离的,实际上是每个线程中的ThreadLocalMap成员变量
     代码public class ThreadLocalTest {private static ThreadLocal<Integer> a = new ThreadLocal<>();private static ThreadLocal<Integer> b = new ThreadLocal<>();public static void main(String[] args) {new Thread(() -> {a.set(1);},"t1").start();new Thread(() -> {a.set(1);},"t2").start();new Thread(() -> {a.set(1);},"t3").start();}
}代码new Thread(() -> {a.set(1);b.set(1);c.set(1);},"t1").start();ThreadLocalMap扩容机制如果频繁在某个线程中使用不同ThreadLocal添加元素当元素个数超过容器2/3进行扩容ThreadLocalMap的默认容量16ThreadLocalMap索引冲突开放地址法

20.@Async注解失效的


1.注解@Async的方法不是public方法2.注解@Async的返回值只能为void或Future3.注解@Async方法使用static修饰也会失效4.spring无法扫描到异步类,没加注解@Async或@EnableAsync注解5.调用方与被调用方不能在同一个类6.类中需要使用@Autowired或@Resource等注解自动注入,不能自己手动new对象7.在Async方法上标注@Transactional是没用的.但在Async方法调用的方法上标注@Transcational是有效的

第三--JVM与线程相关推荐

  1. 聊聊并发(三)——JAVA线程池的分析和使用

    1. 引言 合理利用线程池能够带来三个好处.第一:降低资源消耗.通过重复利用已创建的线程降低线程创建和销毁造成的消耗.第二:提高响应速度.当任务到达时,任务可以不需要等到线程创建就能立即执行.第三:提 ...

  2. jvm一个线程的成本

    Jvm一个线程的成本是1M, 线程多了,调度成本会造成CPU浪费以及内存成本的增大. 无论是进行什么语言的开发,都会严格控制线程的数量.

  3. java死锁怎么用jvm调试,线程死锁演示,线程锁演示,模拟JVM的线程次序调度

    线程死锁演示,线程锁演示,模拟JVM的线程次序调度 模拟JVM的线程次序调度 注释A,不注释B,一般不死锁 注释B,不注释A,死锁 都不注释,随机package org.he.bin;/** * @a ...

  4. Java7并发编程指南——第三章:线程同步辅助类

    Java7并发编程指南--第三章:线程同步辅助类 @(并发和IO流) Java7并发编程指南第三章线程同步辅助类 思维导图 项目代码 思维导图 项目代码 GitHub:Java7Concurrency ...

  5. 操作系统第三次实验——线程基础总结

    操作系统第三次实验--线程基础总结 文章目录 操作系统第三次实验--线程基础总结 查看CPU核数 创建简单线程 ps -eLF 查看线程 向线程中传递参数 传很多个参数 创建两个线程实现相关操作 查看 ...

  6. 三种创建线程方式之Callable接口

    一.类继承关系及API解析 Callable接口 @FunctionalInterface public interface Callable<V> {V call() throws Ex ...

  7. C# 线程手册 第三章 使用线程 实现一个数据库连接池(实战篇)

    在企业级软件开发过程中,为了改善应用程序的性能需要通常使用对象池来控制对象的实例化.例如,在我们每次需要连接一个数据库时都需要创建一个数据库连接,而数据库连接是非常昂贵的对象.所以,为了节省为每次数据 ...

  8. Java 面试知识点解析(三)——JVM篇

    前言: 在遨游了一番 Java Web 的世界之后,发现了自己的一些缺失,所以就着一篇深度好文:知名互联网公司校招 Java 开发岗面试知识点解析 ,来好好的对 Java 知识点进行复习和学习一番,大 ...

  9. 用户级别线程的切换切换到内核线程_【修炼内功】[JVM] 细说线程

    自从踏入程序猿这条不归路,便摆脱不了(进程)线程这只粘人的小妖精,尤其在硬件资源"过剩"的今天 不论你在使用c.C++..Net,还是Java.Python.Golang,都免不了 ...

最新文章

  1. 使用Python批量修改数据库执行Sql文件
  2. 让Mac OS 10.x.x安装在Vmware虚拟机上!
  3. Exception: This is not supported, use MenuItemCompat.getActionProvider()的处理
  4. mysql中主键外键的作用_数据库主键和外键的作用以及索引的作用,它的优缺点是什么?...
  5. Judge Route Circle
  6. DYNP_VALUES_READ 获取屏幕动态值
  7. 美团点评基于Storm的实时数据处理实践
  8. linux python开发环境sql数据迁移到mysql_linux环境下python怎样操作mysql数据库
  9. 深度学习笔记(42) 人脸识别
  10. sqlserver 还原bak文件 查看不到_SQL还原数据库备份方法
  11. java在线编译器手机版_java编译器app_java编译器手机版_java编程-多特软件站安卓网...
  12. 私有云的优缺点_概述实施私有云的优点和缺点
  13. Ubuntu系统的百度网盘网络错误导致无法上传和下载文件问题解决方法
  14. 【胡侃系列】基于多元回归模型的双十一购物狂欢节天猫商城销售额预测
  15. 天猫精灵python开发_天猫精灵X1智能音箱使用感想
  16. Unity LightMap之动态切换LightMap模拟白天夜晚
  17. PyTorch-09 循环神经网络RNNLSTM (时间序列表示、RNN循环神经网络、RNN Layer使用、时间序列预测案例、RNN训练难题、解决梯度离散LSTM、LSTM使用、情感分类问题实战)
  18. Android Socket(ClientServer)
  19. win10系统笔记本电脑修改注册表设置自动锁屏时间的方法
  20. BT——专门为大容量文件的共享而设计的网络协议

热门文章

  1. 【PPic】基于Electron+Vue+iView的图床应用设计
  2. 云计算运维:运维人员常用到的11款服务器监控工具
  3. 经典WinCC如何移植到TIA博途WinCC Professional?
  4. windows自带的比微信好用的截图工具:截取任意形状图片,标尺画直线,窗口图精准截取
  5. Referenced file contains errors (http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd)
  6. access vba代码大全_这本VBA经典图书终于做活动了,还是5折!
  7. 连咖啡:新零售时代中的娱乐“生意经” | 一点财经
  8. bars 除障句完整_简单的治愈系晚安朋友圈问候语锦集83句
  9. 软通动力:电子签是HR数字化的重要抓手
  10. 【darknet-yolo系列】yolov3 训练模型操作流程(包含所有资源下载)