从0到1学习Java多线程
文章平均质量分 93
Java线程是学习Java的必经之路,本专栏免费给大家讲解多线程有哪些知识点。
醋酸菌HaC
这个作者很懒,什么都没留下…
展开
-
(十八)Worker线程管理
转自:美团技术团队线程池为了掌握线程的状态并维护线程的生命周期,设计了线程池内的工作线程Worker。这也是线程回收的核心我们来看一下它的部分代码:private final class Worker extends AbstractQueuedSynchronizer implements Runnable{ final Thread thread;//Worker持有的线程 Runnable firstTask;//初始化的任务,可以为null}Worker这个工作.转载 2022-04-07 14:45:48 · 1424 阅读 · 1 评论 -
(十七)AtomicInteger原子类的介绍和使用
在第十四章提到 AtomicInteger 可以保证原子性。但是我并没有展开讲它的详细用法,因为内容多,所以这一章节就来学习一下原子操作类——AtomicIntegerAtomicInteger是对int类型的一个封装,提供原子性的访问和更新操作,其原子性操作的实现是基于CAS(compare-and -swap)技术。《深入理解Java虚拟机第二版.周志明》说到这个CAS:CAS在本专栏 第 十六章ReentrantLock 介绍过,也可以回顾一下。1、AtomicInteger 有什么用?原创 2021-05-18 22:58:32 · 667 阅读 · 1 评论 -
(十六)ReentrantLock可重入锁使用和介绍
1、ReentrantLock介绍jdk中独占锁的实现除了使用关键字synchronized外,还可以使用ReentrantLock。虽然在性能上ReentrantLock和synchronized没有什么区别,但ReentrantLock相比synchronized而言功能更加丰富,使用起来更为灵活,也更适合复杂的并发场景。两者的相同点:1、ReentrantLock和synchronized都是独占锁,只允许线程互斥的访问临界区。但是实现上两者不同:synchronized加锁解锁的过程是隐原创 2021-02-26 11:31:38 · 935 阅读 · 5 评论 -
(十五)ThreadLocal的用法,如何解决内存泄漏
什么是ThreadLocal变量ThreadLocal称为线程本地变量,其为变量在每个线程中都创建了一个副本,每个线程都访问和修改本线程中变量的副本,但每个线程之间的变量是不能相互访问的,ThreadLocal不是一个Thread。ThreadLocal 有四个方法原创 2020-07-30 00:04:56 · 2003 阅读 · 3 评论 -
(十四)volatile的用法+为什么不能确保原子性+与synchronized的区别
volatile介绍volatile 的作用是保证变量在多线程之间的可见性。synchronized是阻塞式同步,会在线程竞争激烈的情况下,会升级为重量级锁,还可能会死锁;而volatile是一种轻量级的同步机制。在理解这个volatile可见性之前,需要先了解一下CPU高速缓存、Java内存模型的知识。主内存:java虚拟机规定所有的变量(不是程序中的变量)都必须在主内存中产生,为了方便理解,可以认为是堆区。可以与前面说的物理机的主内存相比,只不过物理机的主内存是整个机器的内存,而虚拟机的主内存原创 2020-07-26 13:19:13 · 877 阅读 · 0 评论 -
(十三)synchronized用法、底层原理,附四种锁范围详细例子
《深入理解Java虚拟机》一句话:当多个线程访问同一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替运行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获取正确的结果,那这个对象是线程安全的。1. 开篇内存分为主内存和工作内存,每个线程都有自己的工作内存,如何和主内存的数据同步,产生的数据不一致性,就是我们常说的线程安全,这就需要我们去了解Java内存模型了。借用一张图:如图为JMM抽象示意图,线程A和线程B之间要完成通信的话,要经历如下两步:原创 2020-07-26 13:18:46 · 3107 阅读 · 6 评论 -
(十二)yield、notify、notifyAll、sleep、join、wait 的区别
1. wait ,notify / notifyAll核心源码:public final void wait() throws InterruptedException { wait(0);}Object.wait(long)要跟Object.notify()/notifyAll()搭配使用。wait 与 notify/notifyAll 方法必须在synchronized 同步代码块中使用,即要先对调用对象加锁,不放在synchronized 中则会在program runtime原创 2020-07-26 13:18:09 · 751 阅读 · 0 评论 -
(十一)sleep(1)、sleep(0)和sleep(1000)的区别
众所周知,sleep是让线程处于等待运行状态,不会占用CPU,OS会将执行时间分配给其它线程。sleep(0)字面意思是睡眠0毫秒,大家可能觉得跟没写一样,其实不是的。sleep(1000)比较容易理解,就是让线程睡眠1000毫秒,但是1000毫秒后,线程会执行吗,是立即执行吗?本篇文章主要是探究以上的问题。操作系统中,CPU竞争有很多种策略。Unix系统使用的是时间片算法,Windows属于抢占式。在时间片算法中,所有的进程排成一个队列。操作系统按照他们的顺序,给每个进程分配一段时间,即该进.原创 2020-07-26 13:17:41 · 18752 阅读 · 2 评论 -
(十)线程池参数——workQueue用法
线程池参数的 workQueue 决定了缓存任务的排队策略,对于不同的业务场景,我们可以使用不同的排队策略。我们只需要实现BlockingQueue 这个接口即可。介绍一下常用的有三种workQueue1. SynchronousQueueSynchronousQueue没有容量,是无缓冲等待队列,是一个不存储元素的阻塞队列,会直接将任务交给消费者(即丢给空闲的线程去执行),必须等队列中的添加元素被消费后才能继续添加新的元素,否则会走拒绝策略,所以使用SynchronousQueue阻塞队列一般要原创 2020-07-25 16:10:19 · 4688 阅读 · 2 评论 -
(九)线程池异常捕获
上一篇提到了使用ThreadFactory的UncaughtExceptionHandler去捕获线程池的错误,还有没有其他方法呢?线程的异常捕获可以使用try catch,但是主线程 如何 捕获子线程的异常呢?当一个线程执行出错了,接下来是否还要执行呢?1. try catch在子线程执行的方法体里面加上 try catch ,try catch 可以捕获当前线程的抛出的异常。但是try catch 无法捕获其他线程的错误。demo:public class OtherException {原创 2020-07-25 16:09:37 · 4321 阅读 · 1 评论 -
(八)Callable和Runnable的区别
Callable和Runnable都是一个接口。Runnable@FunctionalInterfacepublic interface Runnable { /** * When an object implementing interface <code>Runnable</code> is used * to create a thread, starting the thread causes the object's * <原创 2020-07-25 16:07:08 · 1385 阅读 · 1 评论 -
(七)线程池的大小如何确定
线程的使用目的是提高运行速度,提高运行的速度是要充分提用CPU和I/O 的利用率。这就涉及到CPU密集型程序和I/O密集型程序的区别了。CPU 密集型程序CPU密集型也叫计算密集型,指的是系统的硬盘、内存性能相对CPU要好很多,此时,系统运作大部分的状况是CPU Loading 100%,CPU要读/写I/O(硬盘/内存),I/O在很短的时间就可以完成,而CPU还有许多运算要处理,CPU Loading很高。比如说要计算1+2+3+…+ 1亿、计算圆周率后几十位、数据分析。都是属于CPU密集型程序原创 2020-07-25 16:04:35 · 3523 阅读 · 1 评论 -
(六)ThreadPoolExecutor自定义线程池
上一篇中提到四种线程池的创建方式,最后还是会 new ThreadPoolExecutor(),所以 我们可以使用 new ThreadPoolExecutor()的方法创建自定义的线程。可以看到 ThreadPoolExecutor 是 ExecutorService的实现类:public class ThreadPoolExecutor extends AbstractExecutorService {}public abstract class AbstractExecutorServic原创 2020-07-25 16:04:03 · 1154 阅读 · 0 评论 -
(五)四种线程池底层详解
Java中提供了四种线程池创建方法线程池名称描述newSingleThreadExecutor创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。newFixedThreadPool创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。newScheduledThreadPool创建一个可定期或者延时执行任务的定长线程池,支持定时及周期性任务执行。newCachedT原创 2020-07-25 16:03:29 · 1124 阅读 · 0 评论 -
(四)为什么要使用线程池
阿里开发手册有一段描述:【强制】线程资源必须通过线程池提供,不允许在应用中自行显式创建线程。说明:使用线程池的好处是减少在创建和销毁线程上所花的时间以及系统资源的开销,解决资源不足的问题。如果不使用线程池,有可能造成系统创建大量同类线程而导致消耗完内存或者“过度切换”的问题。上一篇文章介绍了Java线程是什么,以及用显式创建线程的两种方式(继承Thread类或者实现Runnable接口):1. 手动创建线程的缺点继承extend类或者实现runnable接口都是最简单创建线程的方式,但是这种方原创 2020-07-25 16:02:43 · 1044 阅读 · 0 评论 -
(三)Java线程创建方式
我们平时用main方法执行的代码,都是以主线程去执行。如果要使用多线程,可以使用以下三种方式去创建:1. 继承Thread类class MyThread extends Thread { @Override public void run() { System.out.println(Thread.currentThread().getName() + "---->>>>" +"继承Thread类"); }}2. 实现Runnabl原创 2020-07-25 16:01:28 · 981 阅读 · 0 评论 -
(二)Java线程与系统线程,生命周期
1.操作系统中线程的5种状态在操作系统中,线程的生命周期可以分为5种状态:①new 关键字创建了Thread类(或其子类)的对象,或者Runnable。②Runnable 调用了start()方法,这时的线程就等待时间片轮转到自己这,以便获得CPU;第二种情况是线程在处于RUNNING状态时并没有运行完自己的run方法,时间片用完之后回到RUNNABLE状态;还有种情况就是处于BLOCKED状态的线程结束了当前的BLOCKED状态之后重新回到RUNNABLE状态。③Running:这时的线程指的是获原创 2020-07-25 16:00:03 · 750 阅读 · 0 评论 -
(一)线程是什么
多线程可以实现并行处理,避免了某项任务长时间占用CPU时间。在单CPU计算机中,为了运行所有这些线程,操作系统需要为每个独立线程安排一些CPU时间,操作系统以轮换方式向线程提供时间片,在宏观上似乎这些线程都在同时运行。简单的说,就是更好的利用CPU的资源。1. 程序计算机程序,是指为了得到某种结果而可以由计算机等具有信息处理能力的装置执行的代码化指令序列,或者可以被自动转换成代码化指令序列的符号化指令序列或者符号化语句序列。2. 进程为了使程序并发执行,并且可以对并发执行的程序加以描述和控制,人.原创 2020-07-25 15:58:39 · 1940 阅读 · 0 评论