
Java线程与并发
文章平均质量分 90
Java多线程学习专栏。
程序员小潘
Java开发工程师,现居杭州,优快云博客专家,热衷于分享计算机编程相关知识,欢迎关注~
展开
-
告诉你一个将ThreadLocal性能提升三倍的秘密
使用线性探测技术,在哈希冲突比较多的情况下,读写的性能会受到影响。查询时,如果发生哈希冲突,就需要循环访问下一个节点,增加了寻址次数,降低了查询的性能。原创 2020-11-25 23:05:10 · 2717 阅读 · 0 评论 -
巧用分段锁实现高效自增计数器
分段锁数据分段上锁,将锁的粒度进一步细化,以此来提升并发的效率。使用分段锁来提升并发性能的例子,如JDK提供的ConcurrentHashMap,线程安全的Map容器,但是性能比HashTable要高不少。内部的每一个Segment都是一把锁,也都是一个小的HashMap,通过对Key计算哈希码,定位到一个Segment,每次只对其中一个Segment加锁,而不影响其他Segment的插入,通过分段加锁的方式来实现并发插入。理论上,16个Segment最高可支持16个线程并发插入数据,而HashTab原创 2020-09-28 20:50:58 · 603 阅读 · 1 评论 -
关于CAS的一点理解和思考
文章目录CASJava中的CAS操作加锁和CAS性能测试比较CAS不同线程数量下的额外开销CASCAS(Compare And Swap)是对一种处理器指令的称呼,中文译为:比较并交换。它需要三个参数:内存地址V、期望的旧值A、要替换的新值B。它要完成的功能:当且仅当内存地址V的值等于A时,将A替换为B并返回true,否则什么也不做直接返回false。用Java代码描述,大致如下所示:...原创 2020-03-27 21:08:23 · 3332 阅读 · 0 评论 -
线程间协作——等待与通知
文章目录前言wait和notify存在的问题notify和notifyAll用哪个?生产者消费者实战条件变量Condition前言系统的稳定运行,在单线程程序中得益于类与类之间的协作,在多线程程序中,还得益于线程与线程之间的协作。一段逻辑代码块的执行可能会依赖于某个先决条件,在单线程程序中可以使用if来构建分支,在多线程程序中可以使用Java提供的等待-通知功能。例如:生产者消费者模式中,...原创 2020-03-27 19:36:29 · 3159 阅读 · 0 评论 -
聊聊Synchronized和Lock
目录Synchronized和Lock的区别阻塞线程状态不同阻塞算法-悲观锁非阻塞算法-乐观锁Synchronized和Lock的区别Synchronized和Lock都可以用来做代码块的同步控制,但是它俩的底层实现不一样,性能也不一样,需要根据不同的应用场景来选择合适的同步器,下面总结一下它俩的区别:来源不同Synchronized是Java提供的关键字,属于Java语法层...原创 2020-01-31 21:18:39 · 3637 阅读 · 1 评论 -
线程池以及手写实现
前言什么是线程池存放若干个用于执行任务的线程的容器。为什么要用线程池性能线程的创建和销毁是非常消耗系统资源的,每当我们要执行异步任务时,都创建一个新的线程,会带来大量额外的开销,并且线程的数量不宜过多,线程过多会增加CPU调度的压力,导致多线程程序反而性能下降。线程池可以预先创建好若干个线程实例,随时准备执行任务。安全线程是非常珍贵的资源,CPU调度线程的能力是有限的,意味着线程的...原创 2019-11-26 20:50:42 · 3175 阅读 · 0 评论 -
并发容器
List、Map、Set,我们经常使用这些容器来存放数据,以及对数据进行增删改查。但有一点需要注意的是:java.util包下的很多容器都是线程不安全的。解决的办法就是使用synchronized和显式锁来保证线程安全,但是这么做太麻烦了,效率也很低。JDK为我们提供了一些线程安全的并发容器,可以直接使用,不用我们自己来维护并发问题。ListCopyOnWriteArrayList实现...原创 2019-11-26 20:48:23 · 3100 阅读 · 0 评论 -
基于AQS实现自定义锁
AQS全称:AbstractQueuedSynchronizer,译为:抽象队列同步器。AQS是很多并发工具类的基础,可以说是实现整个java.util.concurrent并发包的半壁江山。public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implemen...原创 2019-11-23 18:35:18 · 3405 阅读 · 0 评论 -
Lock和Condition实现等待通知
Condition接口目的:替代传统的Object的wait()、notify()。相较于Object的wait()、notify(),使用Condition的await()、signal()来实现线程间的协作更加的安全,效率也更高。使用wait、notify的前提是必须获取到监视器对象,否则会抛异常。因为wait会释放锁,释放锁的前提肯定是必须先拥有锁。和wait、notify一样,使用...原创 2019-11-23 18:34:42 · 3242 阅读 · 0 评论 -
Java显式锁
synchronized和LocksynchronizedJava提供的关键字,属于Java语法层面的互斥,隐式锁,由JVM来实现加锁和释放锁。优点代码编写简单可读性好缺点加锁和释放锁由JVM来完成,不够灵活。获取锁的过程不可中断。不支持超时,获取不到锁会一直阻塞。非公平锁,不允许修改。不支持尝试获取锁的判断。不支持读写锁,比较僵硬。LockLock属于Java...原创 2019-11-23 18:33:37 · 3085 阅读 · 0 评论 -
读写锁以及手写实现
读写锁Java内置了读写锁工具类,方便开发人员针对“读多写少”的场景提升加锁的性能。为什么需要读写锁?synchronized和ReentrantLock都属于排他锁,存在明显的性能问题:读读互斥。当某一个线程获取锁时,其他线程全部阻塞,性能不高。读写锁可以实现:读读不互斥,仅读写、写写互斥。对于“读多写少”的场景,允许多个读线程同时操作资源,可以大大提升应用性能。功能定义加读锁时...原创 2019-11-22 19:54:17 · 4142 阅读 · 2 评论 -
Java原子操作和CAS
为了开发者更方便的编写多线程程序,Java提供了一些原子操作类,在java.util.concurrent.atomic包下。什么是原子操作?操作:实现特定功能的1行或N行代码,或一个方法。原子操作:多线程下,某个线程在执行该操作时,不允许被其他线程打断。程序运行时,CPU在多个线程中快速的切换,每个线程在运行下一条指令前,都有可能失去CPU的执行权。对于一个方法或代码块,如果不做任何处...原创 2019-11-21 19:22:39 · 3166 阅读 · 0 评论 -
Java实现锁的几种方式
锁和同步,学习多线程避不开的两个问题,Java提供了synchronized关键字来同步方法和代码块,还提供了很多方便易用的并发工具类,例如:LockSupport、CyclicBarrier、CountDownLatch、Semaphore…有没有想过自己实现一个锁呢?笔者通过一个“抢票”的程序,分别用几种不同的方式来实现方法的同步和加锁,并分析它们的优劣。自旋就是让加锁失败的线程死循环...原创 2019-11-19 19:56:15 · 12996 阅读 · 0 评论 -
Callable、FutureTask及手写实现
创建线程的两种方式:Thread和Runnable,但它们都有一个缺点:无法获取返回值。如果需要进行异步运算,而且需要获取运算的结果值,可以使用Callable和FutureTask。FutureTask APIboolean isCancelled()是否取消。boolean isDone()是否计算结束。boolean cancel(boolean mayInterr...原创 2019-11-18 18:54:22 · 3181 阅读 · 0 评论 -
SpringMVC的线程安全问题
SpringMVC,这个大家每天都在使用的框架,不知大家在使用的时候,是否有考虑过它线程安全的问题呢?我们都知道,SpringMVC通过前端控制器DispatcherServlet来分发处理请求,通过对请求URL和@RequestMapping的映射关系,来调用Controller中对应的方法。Spring的IOC容器中,默认都是单例的,Controller也不例外。服务器肯定是需要接收大量...原创 2019-11-15 12:25:46 · 5031 阅读 · 2 评论 -
浅谈wait、sleep、yield
wait译为:等待挂起当前线程,让出CPU资源,释放锁,直到其他线程调用notify来唤醒。使用场景:当前线程需要其他线程完成一些工作才能继续执行,所以需要等待。调用wait的前提条件是:当前线程获得了对象监视器,只有获得锁才能释放锁,否则会抛异常。void wait() throws InterruptedException无限等待,直到被notify唤醒。void wa...原创 2019-11-14 19:00:46 · 3138 阅读 · 0 评论 -
Exchanger数据交换
中文译为:交换器。主要作用:两个线程之间进行数据交换。Exchanger提供了一个同步点,当线程执行到同步点时,会被阻塞,直到双方完成了数据交换,才继续往下执行。Tom和Jerry例子启动两个线程,让其完成一次简短的对话。Tompublic class Tom implements Runnable { private Exchanger<String> exchange...原创 2019-11-14 18:59:56 · 3189 阅读 · 0 评论 -
Semaphore使用及手写实现
Semaphore(信号量)是用来控制同时访问特定资源的线程数量,它通过协调各个线程,以保证合理的使用公共资源。作用:控制同时访问某个资源的最大线程数,一般用来限流。API构造器Semaphore(int permits)许可证数量Semaphore(int permits, boolean fair)许可证数量,使用公平锁/非公平锁Methodsvoid a...原创 2019-11-13 18:43:41 · 6615 阅读 · 0 评论 -
为什么说i++不是原子操作
在编写多线程程序时,对于不是原子操作的,需要引起程序员的额外注意。一定要确保其对数据的操作是同步的,否则会引发数据安全问题。i++不是原子操作先来看一个例子,多线程下出现的数据不一致问题。public class Test { static int i = 0; public static void main(String[] args) { for (int j = 0; j...原创 2019-11-06 12:11:54 · 5589 阅读 · 1 评论 -
CountDownLatch和CyclicBarrier
并发编程常用工具类之CountDownLatch和CyclicBarrier的使用笔记。CountDownLatch在java1.5被引入,存在于java.util.cucurrent包下,也被称为:闭锁。常用的并发工具类。利用计数器的方式实现的多线程之间的同步方案。典型的应用场景:某个线程的执行需要等待其他线程执行完毕完才开始。例如:业务线程需要等待两个初始化线程执行完之后才能开始执...原创 2019-11-05 13:16:54 · 3837 阅读 · 0 评论 -
ForkJoin之RecursiveAction和RecursiveTask的简单使用
ForkJoin之RecursiveAction和RecursiveTask的简单使用Java提供的多线程可以提高CPU的利用率,现在的CPU都是多核多线程,如果不好好利用,只运行单线程程序,会使得CPU的其他核心空闲,浪费宝贵的计算机资源。编写好的程序不容易,编写好的多线程程序更难。JDK1.7开始,Java提供了Fork/Join框架,可以方便的将一个大任务拆分成多个小任务,利用多个线程...原创 2019-10-26 23:08:22 · 6241 阅读 · 0 评论 -
Java多线程间的通信
Java中的多线程共享的是堆内存,栈内存是线程私有的,A线程无法获取B线程的运行情况。这对于 多线程之间的协作不是很友好。线程间的通信就是为了线程之间更加友好的协作。线程间通信如果线程之间不能通信,A线程为了判断B线程的运行状态就必须轮询的去监听,但是轮询存在两个大问题:信息获取不及时。浪费CPU的资源。waitwait方法来自Object类,被final修饰,意味着子类不能重...原创 2019-10-25 22:23:39 · 4930 阅读 · 3 评论 -
Java中的volatile关键字
并发编程的三个基本概念:原子性可见性有序性编写多线程程序时,经常会看到 volatile 关键字。在Java中,volatile 被用来修饰 变量。使用 volatile 修饰的变量有什么特点呢?JMM内存划分在Java内存模型中,内存区域的划分大致如下图所示:除了共享的 主内存 外,每个Java线程都有一块自己私有的工作内存。当线程需要对 主存 中的变量进行读写时,会先...原创 2019-10-24 19:06:11 · 8130 阅读 · 0 评论 -
对象锁与类锁
类锁public class ClassLock { static long t1 = System.currentTimeMillis(); synchronized static void lock() { int time = (int) Math.ceil((System.currentTimeMillis() - t1)/1000); System.out.println...原创 2019-10-24 19:04:40 · 4951 阅读 · 0 评论 -
Java守护线程
在Java中线程分两种:用户线程、守护线程。守护线程:顾名思义,目的就是为了守护 用户线程,守护线程依附于用户线程,当用户线程死亡后,守护线程也就没有存在的意义了,会自行消亡。用户线程销毁时,守护线程一定销毁。守护线程销毁时,用户线程不一定销毁。隐藏的守护线程当我们运行一个简单的main方法时,JVM会自动帮我们开启一些守护线程。使用如下代码查看:public static void...原创 2019-10-24 19:03:46 · 4835 阅读 · 0 评论 -
Java启动线程的三种方式
Thread继承自Thread。public class ThreadDemo extends Thread { @Override public void run() { System.out.println(Thread.currentThread().getName() + "-启动了..."); } public static void main(String[] arg...原创 2019-10-24 19:02:52 · 5258 阅读 · 0 评论 -
ThreadLocal
最近在学多线程,看到 ThreadLocal 类,觉得有必要记录一下。ThreadLocal简单例子public class ThreadLocalDemo { static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>(){ @Override protected Integer i...原创 2019-10-21 22:51:27 · 4716 阅读 · 0 评论