多线程
文章平均质量分 96
简要探讨JAVA多线程的奥秘
SunAlwaysOnline
开始工作的第3年!
展开
-
一次因线程池使用不当造成生产事故的排查记录与思考
某日当我点开熟悉的界面,一个又一个请求失败的提示赫然出现在屏幕上,不会是昨晚上线的代码有问题吧?吓得我急忙按F12查看了响应——"exception":"java.lang.OutOfMemoryError","message":"unable to create new native thread"出现了内存溢出的情况,无法创建更多的本地线程。接着查看了实例的监控大盘,发现每个实例的JVM线程数量都处于9000+的规模,且还有上涨的趋势。这是其中一个实例的线程数量监控图:10.原创 2021-11-09 23:51:03 · 4080 阅读 · 7 评论 -
还好我接住了面试官对线程池的夺命连环问
说说线程池的类图结构说说线程池的核心参数这些核心参数位于ThreadPoolExecutor的构造方法中: public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit原创 2021-09-02 22:45:53 · 2215 阅读 · 4 评论 -
我用了上万字,走了一遍Redis实现分布式锁的坎坷之路,从单机到主从再到多实例,原来会发生这么多的问题
一、分布式锁的背景在同一个jvm进程内,我们可以使用synchronized或者lock锁,来完成对共享资源的互斥访问。然而现在大多数系统都是分布式系统,jvm进程分布在不同的节点上,为了全局数据的一致性,这个时候就需要分布式锁了。实现分布式锁,有多种方案(1)借助于数据库,乐观锁使用版本号机制,悲观锁使用for update机制。(2)借助于Zookeeper,通过创建临时的顺序节点。(3)借助于Redis,这篇文章会详细说明Redis锁的演进历程。二、Redis实现分布式锁的原创 2021-08-29 21:59:52 · 2189 阅读 · 3 评论 -
ThreadLocal源码、InheritableThreadLocal与内存泄露,这一篇给你捋顺了
ThreadLocal,可以理解为线程局部变量。同一份变量在每一个线程中都保存一份副本,线程对该副本的操作对其他线程完全是不可见的,是封闭的。一、ThreadLocal简单示例public class Main { private static ThreadLocal<Integer> tl = new ThreadLocal<>(); public static void main(String[] args) { tl.set(1)原创 2021-08-16 23:10:49 · 2480 阅读 · 2 评论 -
面试常问集锦——多线程部分
多线程1、synchronizedhttps://blog.csdn.net/tongdanping/article/details/79647337synchronized锁的是什么?说说对它的理解修饰实例方法与对象时,需要获取的是实例对象的监视器锁。修饰静态方法与class时,需要获取的是Class对象的监视器锁。线程a访问实例对象的同步方法,线程b访问静态同步方法时,两者不互斥。在JDK1.6以前,使用synchronized就只有一种方式即重量级锁,而在JDK1.6以后,原创 2021-04-01 22:35:39 · 3380 阅读 · 0 评论 -
面试官:如何停止一个正在运行的线程?我又懵了
上一篇讲了如何等待子线程运行结束,原文https://blog.csdn.net/qq_33591903/article/details/108496110。本篇讲讲如何终止子线程暴力停止——Stop方法package com.qcy.testStopThread;/** * @author qcy * @create 2020/09/16 09:40:34 */public class Main1 { static class MyThread extends Threa原创 2020-09-16 16:45:10 · 1834 阅读 · 0 评论 -
你真得懂Thread.join吗?
Thread类中的join方法,用于等待某个线程执行结束。简单示例以下简单的代码,会让主线程等待子线程执行结束再执行。如果去掉t.join(),可能主线程就直接退出了,子线程都来不及执行。package com.qcy.testJoin;/** * @author qcy * @create 2020/09/10 17:17:03 */public class Main { public static void main(String[] args) throws Inte原创 2020-09-11 10:32:27 · 3727 阅读 · 0 评论 -
面试官:如何让主线程等待所有的子线程执行结束之后再执行?我懵了
使用Thread的join方法package com.qcy.testThreadFinish;/** * @author qcy * @create 2020/09/09 17:05:23 */public class Case1 { public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(() -> {原创 2020-09-09 17:54:40 · 6920 阅读 · 4 评论 -
SpringBoot中的异步调用@Async
如何开启异步调用在SpringBoot中,只需要给方法加上@Async注解,就能将同步方法变为异步调用。首先在启动类上添加@EnableAsync,即开启异步调用。/** * @author qcy */@SpringBootApplication@EnableAsyncpublic class AsyncApplication { public static void main(String[] args) { SpringApplication.run(原创 2020-09-09 17:52:37 · 1238 阅读 · 0 评论 -
什么,你还不会用CompletableFuture?
CompleteFuture原创 2020-09-08 14:11:01 · 2242 阅读 · 0 评论 -
谈谈Runnable、Future、Callable、FutureTask之间的关系
谈谈Runnable、Future、Callable、FutureTask之间的关系原创 2020-09-07 15:12:33 · 2111 阅读 · 0 评论 -
基于SpringBoot与数据库表记录的方式实现简单的分布式锁
同一进程内的不同线程操作共享资源时,我们只需要对资源加锁,比如利用JUC下的工具,就可以保证操作的正确性。对JUC不熟悉的同学,可以看看以下的几篇文章:浅说Synchronized Synchronized的优化 Unsafe类 浅探CAS实现原理 CountDownLatch实现原理 ThreadLocal使用不好,小心造成内存泄露! 更多文章,在我的多线程专栏中但是,为了高可用,我们的系统总是多副本的,分布在不同的机器上,以上同进程内的锁机制就不再起作用。为了保证多副本系统对共享资源的原创 2020-08-25 22:58:40 · 706 阅读 · 0 评论 -
谈谈并行流parallelStream
一、parallelStream内部使用了哪些线程Java8中提供了能够更方便处理集合数据的Stream类,其中parallelStream()方法能够充分利用多核CPU的优势,使用多线程加快对集合数据的处理速度。不熟悉Stream类的同学,可以先参考我的另外一篇文章Java8中Stream的常用方法以一个简单的例子,来看看parallelStream内部到底使用了哪些线程 Integer[] array = new Integer[]{1, 2, 3, 4, 5};原创 2020-08-14 12:32:07 · 30018 阅读 · 0 评论 -
如何排查java应用的死锁
首先,我们构造一个死锁场景。如何构造一个死锁呢?原创 2020-08-04 22:13:12 · 501 阅读 · 0 评论 -
ThreadLocal使用不好,小心造成内存泄露!
一、前言对ThreadLocal不熟悉的同学,可以先参考我的另外一篇文章浅谈ThreadLocal在讨论内存泄漏之前,需要明白java中的四种引用,同样可以移步到java中的四种引用原创 2020-06-14 00:24:23 · 1965 阅读 · 0 评论 -
【多线程】LongAdder实现原理
前言AtomicInteger、AtomicLong使用非阻塞的CAS算法原子性地更新某一个变量,比synchronized这些阻塞算法拥有更好的性能,但是在高并发情况下,大量线程同时去更新一个变量,由于同一时间只有一个线程能够成功,绝大部分的线程在尝试更新失败后,会通过自旋的方式再次进行尝试,严重占用了CPU的时间片。AtomicLong的实现原理图:LongAdder是JDK8新增的原子操作类,它提供了一种新的思路,既然AtomicLong的性能瓶颈是由于大量线程同时更新一个变量造成的,原创 2020-05-24 00:42:17 · 1417 阅读 · 1 评论 -
【多线程】说说线程池
前言线程池内部是多个线程的集合,在创建初期,线程池会创建出多个空闲的线程,当有一个任务需要执行时,线程池会选择出一个线程去执行它,执行结束后,该线程不会被销毁,而是可以继续复用。使用线程池可以大大减少线程频繁创建与销毁的开销,降低了系统资源的消耗。当任务来临时,直接复用之前的线程,而不是先创建,提高了系统的响应速度。此外,线程池可以控制最大的并发数,避免资源的过度消耗。简单实例先给出一个线程池的简单例子:package com.xue.testThreadPool;import j原创 2020-05-21 11:03:06 · 3665 阅读 · 0 评论 -
【多线程】Semaphore实现原理
前言Semaphore,信号量,一般用于控制同时访问资源的线程数量。可以认为Synchronized代表的是一把锁,那么Semaphore就是多把锁。常用方法public class Semaphore implements java.io.Serializable { //构造方法,传入令牌数,默认实例化一个非公平锁 public Semaphore(int permits); //获取一个令牌,在获取成功之前,以及被其他线程中断之前,当前线程会被阻塞 pub原创 2020-05-20 13:51:53 · 1514 阅读 · 0 评论 -
【多线程】CyclicBarrier实现原理
前言CyclicBarrier,字面意思“循环屏障”,用于多个线程一起到达屏障点后,多个线程再一起接着运行的情况。例如,线程1和线程2一起运行,线程1运行到屏障点a时,将会被阻塞,等到线程2运行到屏障点a后,线程1和线程2才可以打破屏障,接着运行。如果有屏障点b,则他们需要像打破屏障a一样打破屏障b,如此循环往复。常用方法public class CyclicBarrier { //构造方法,传入线程总数以及打破屏障点前的任务 public CyclicBarrier(in原创 2020-05-19 11:39:29 · 673 阅读 · 0 评论 -
【多线程】CountDownLatch实现原理
前言CountDownLatch是多线程中一个比较重要的概念,它可以使得一个或多个线程等待其他线程执行完毕之后再执行。它内部有一个计数器和一个阻塞队列,每当一个线程调用countDown()方法后,计数器的值减少1。当计数器的值不为0时,调用await()方法的线程将会被加入到阻塞队列,一直阻塞到计数器的值为0。常用方法public class CountDownLatch { //构造一个值为count的计数器 public CountDownLatch(int count原创 2020-05-15 14:52:56 · 3214 阅读 · 0 评论 -
【多线程】浅探CAS实现原理
前言CAS,全称是Compare And Swap,即比较并交换,是一种乐观锁的实现。悲观锁与乐观锁悲观锁总是假设最坏的情况,线程a每次去获取或更新数据的时候,都会觉得别的线程也正在修改这个数据,为了避免自己的更新操作丢失,线程a会尝试获取此数据的锁,线程a获取到之后,才能对此数据进行一些更新操作。在此期间,别的线程无法更新,只能等到线程a释放锁之后,才能进行更新。之所以叫做悲观锁,是因为这是一种对数据的修改抱有悲观态度的并发控制方式。我们一般认为数据被并发修改的概率比较大,所以需要在修原创 2020-05-14 17:40:39 · 1475 阅读 · 0 评论 -
JUC基石——Unsafe类
前言我们经常在JUC包下的ConcurrentHashMap、Atomic开头的原子操作类、AQS以及LockSupport里面看到Unsafe类的身影,这个Unsafe类究竟是干什么的,本文可以带着读者一探究竟。Java和C++、C语言的一个重要区别,就是Java中我们无法直接操作一块内存区域,而在C++、C中却可以自己申请内存和释放内存。Unsafe类的设计,为我们提供了手动管理内存...原创 2020-04-22 14:19:19 · 2512 阅读 · 0 评论 -
深入分析AQS实现原理
简单解释一下J.U.C,是JDK中提供的并发工具包,java.util.concurrent。里面提供了很多并发编程中很常用的实用工具类,比如atomic原子操作、比如lock同步锁、fork/join等。从Lock作为切入点我想以lock作为切入点来讲解AQS,毕竟同步锁是解决线程安全问题的通用手段,也是我们工作中用得比较多的方式。Lock APILock是一个接口,方法定义...转载 2020-04-23 14:15:43 · 568 阅读 · 0 评论 -
【多线程】Synchronized的优化
对synchronized不太了解的同学,可以先参考我的另外一篇文章【多线程】浅说Synchronized早期版本synchronized性能较低的原因在早期版本中,synchronized是一种重量级锁,其底层由Monitor实现,而Monitor又依赖于操作系统的Mutex Lock。线程获取到锁后,需要切换状态,而操作系统在实现线程的切换时,需要从用户态转为核心态,这是一个非常耗时,...原创 2020-04-13 16:34:09 · 1232 阅读 · 0 评论 -
【多线程】浅说Synchronized
一、前言synchronized关键字用来保证在同一时刻只有一个线程可以执行被它修饰的变量或者代码块。这一篇中,只涉及synchronized的底层实现原理,不涉及对synchronized效率以及如何优化的讨论。二、使用方式(1)给静态方法加锁public class Main { public static synchronized void static...原创 2020-04-13 14:07:12 · 1119 阅读 · 0 评论 -
【JAVA】浅谈ThreadLocal
浅谈ThreadLocal1、ThreadLocal是什么? 在并发情况下,多个线程对一个共享变量的操作往往是非常危险的。为了保证线程安全,我们需要对该共享变量加synchronized锁,确保在同一个时间内,只有一个线程可以对该共享变量进行读写。ThreadLocal在解决...原创 2019-08-21 11:40:23 · 2856 阅读 · 1 评论 -
两个线程交替打印奇偶数
题目:使用两个线程交替打印1-10依照题意:线程0打印1,线程1打印2,接着再次这样循环,一直到输出10为止。我首先想到的是线程间的通信,首先让线程0执行,输出1,然后notify唤醒线程1,之后线程0立马wait释放锁。线程1拿到锁之后,输出2,同样,notify唤醒线程0,接着自己立马wait释放锁。先写个示例代码:package com.yang.testThreadPri...原创 2019-12-11 14:22:32 · 1596 阅读 · 3 评论 -
【JAVA多线程】如何解决一个生产者与消费者问题
如何解决一个生产者与消费者问题生产者与消费者问题是多线程同步的一个经典问题。生产者和消费者同时使用一块缓冲区,生产者生产商品放入缓冲区,消费者从缓冲区中取出商品。我们需要保证的是,当缓冲区满时,生产者不可生产商品;当缓冲区为空时,消费者不可取出商品。下面介绍java中几种解决同步问题的方式(1)wait()与notify()方法...原创 2018-11-01 15:28:19 · 19106 阅读 · 1 评论 -
【JAVA】创建线程的两种方式Thread与Runnable
创建线程的两种方式Thread与Runnable一、简要说明创建线程的两种方式,一是继承Thread类,二是实现Runnable接口,最后都是依据Thread类的构造方法实例化出一个线程对象,调用线程对象的start()方法,就可以通知线程启动了,在线程获取CPU的资源后,此时线程真正地按照run()方法内部的步骤运行起来了,执行完毕之后,...原创 2018-08-30 22:46:41 · 17109 阅读 · 0 评论 -
【JAVA】多线程之内存可见性
多线程之内存可见性一、什么是可见性?一个线程对共享变量值的修改,能够及时地被其他线程所看到。共享变量:如果一个变量在多个线程的工作内存中都存在副本,那么这个变量就是这几个线程的共享变量。工作内存:每个线程拥有自己的工作内存,只能对自己工作内存中的变量副本进行修改,而不能直接修改主内存中的变量。变量副本:主内...原创 2018-08-29 21:51:50 · 9551 阅读 · 1 评论 -
【JAVA】sleep与wait的区别
sleep与wait的区别了解sleep与wait之间的区别,对于我们编写正确的多线程程序具有十分重要的意义。【1】原理不同(1)sleep用于线程控制自身的流程,使自己暂停指定的时间,把执行机会让给其他线程,时间到,则自动苏醒。(2)wait为Object类的方法(Object类中的其他方法见Obje...原创 2018-08-13 22:44:53 · 7368 阅读 · 0 评论 -
【JAVA】volatile和synchronized的区别
volatile和synchronized的区别共性:volatile与synchronized都用于保证多线程中数据的安全区别:(1)volatile修饰的变量,jvm每次都从主存(主内存)中读取,而不会从寄存器(工作内存)中读取。而synchronized则是锁住当前变量,同一时刻只有一个线程能够访问当前变量...原创 2018-08-07 19:45:45 · 15266 阅读 · 0 评论 -
【JAVA】线程池
线程池1、为什么要创建线程池?(1)创建线程的开销很大(2)预先建立好线程,有一个固定的预先线程数目,等待任务派发,任务完成后再回到线程池2、线程池的参数(1)corePoolSize 初始线程数量(2)maximumPoolSize 最大允许的线程数量...原创 2018-08-05 23:01:58 · 5659 阅读 · 0 评论 -
【JAVA】死锁分析
死锁分析1、死锁的产生有以下代码,模拟的是两个账户之间的转账情况void transfer(Account from,Account to,int money){ from.setAmount(from.getAmount()-money); to.setAmou...原创 2018-08-05 16:51:31 · 10997 阅读 · 0 评论 -
TPS与QPS的理解及区别
TPS与QPS的理解及区别TPS:(Transactions Per Second),即每秒执行的事务总数。首先一个事务包括三个动作,即客户端请求服务端,服务端内部进行处理,服务端对客户端进行响应。将这三个动作看成一个整体,并将之称为一个事务,若在一秒内,服务端可以完成N个事务,则...原创 2019-10-09 11:08:35 · 5681 阅读 · 2 评论