java并发编程
文章平均质量分 83
孙悟空2015
追根溯底,回归本质,挖掘兴趣,激发思考。
展开
-
并发编程——线程安全性
可以在多个线程中调用,并且线程间不会出现额外的错误交互 当多个线程访问某个类时,不管运行环境采用何种调度方式或者线程如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么这个类就是线程安全的。 无状态对象一定是线程安全的:它既不包含任何域,也不包含任何对其他对象域的引用。 原子性 竞态条件 count++:读取—修改—写入 三步操作,并且其结果依赖于之前原创 2015-03-15 11:30:00 · 864 阅读 · 0 评论 -
Java线程并发中的锁——Lock(下)
接上篇文章独占式同步状态获取与释放通过调用同步器的acquire(int arg)方法可以获取同步状态,该方法对中断不敏感,也就是由于线程获取同步状态失败后进入同步队列中,后续对线程进行中断操作时,线程不会从同步队列中移出,代码示例:public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(a原创 2017-05-20 11:27:36 · 3843 阅读 · 0 评论 -
Java线程并发中的锁——ReentrantLock(重入锁)原理详解
ReentrantLock是一个重入锁,可以支持一个线程对资源重复加锁,他还支持公平加锁和非公平加锁。synchronized关键字也隐式的支持重进入,比如一个synchronized修饰的递归方法,在方法执行时,执行线程在获取了锁之后仍能连续多次地获得该锁ReentrantLock虽然没能像synchronized关键字一样支持隐式的重进入,但是在调用lock()方法时,已经获取到锁的线程,能够再原创 2017-05-20 18:32:37 · 8766 阅读 · 1 评论 -
如何利用Redis分布式锁实现控制并发
redis命令解释说道Redis的分布式锁都是通过setNx命令结合getset来实现的,在讲之前我们先了解下setNx和getset的意思,在redis官网是这样解释的 注:redis的命令都是原子操作SETNX key value将 key 的值设为 value ,当且仅当 key 不存在。 若给定的 key 已经存在,则 SETNX 不做任何动作。 SETNX 是『SET if Not原创 2017-06-05 18:39:33 · 14235 阅读 · 2 评论 -
Java多线程读写锁ReentrantReadWriteLock原理详解
ReentrantLock属于排他锁,这些锁在同一时刻只允许一个线程进行访问,而读写锁在同一时刻可以允许多个线程访问,但是在写线程访问时,所有的读和其他写线程都被阻塞。读写锁维护了一对锁,一个读锁和一个写锁,通过分离读锁和写锁,使得并发性相比一般的排他锁有了很大提升。 下面我们来看看读写锁ReentrantReadWriter特性 公平性选择:支持非公平(默认)和公平的锁获取模式,吞吐量还是非公原创 2017-05-21 11:58:45 · 15293 阅读 · 4 评论 -
Java多线程Condition接口原理详解
Condition接口提供了类似Object的监视器方法,与Lock配合可以实现等待/通知模式,但是这两者在使用方式以及功能特性上还是有差别的 Condition接口详解Condition定义了等待/通知两种类型的方法,当前线程调用这些方法时,需要提前获取到Condition对象关联的锁。Condition对象是由Lock对象(调用Lock对象的newCondition()方法)创建出来的,换句话原创 2017-05-21 19:15:23 · 11493 阅读 · 3 评论 -
ConcurrentHashMap原理详解
ConcurrentHashMap是既高效又线程安全的HashMapHashTable和ConcurrentHashMap区别HashTable容器使用synchronized来保证线程安全,但在线程竞争激烈的情况下HashTable的效率非常低下。因为当一个线程访问HashTable的同步方法,其他线程也访问HashTable的同步方法时,会进入阻塞或轮询状态,因为HashTable只有一把锁。原创 2017-05-22 21:30:43 · 2001 阅读 · 1 评论 -
volatile的原理和使用场景
上下文切换 CPU为每个线程分配时间片(几十ms),CPU不断切换线程执行,切换的时候会记录状态,保证能够从原来的状态继续执行。当然上下文切换是有开销的,当线程执行时间非常短时我们用并发可能会耗时更久。使用【Lmbench3】和【vmstat】可以测量上下文切换的时间和次数。 为了降低开销我们应减少上下文切换,多线程竞争锁会引起上线文切换,CAS算法无需加锁,可以减少上线文切换,使用最少线程(...原创 2018-07-11 22:08:42 · 3273 阅读 · 0 评论 -
Java中的自旋锁
自旋锁(spinlock):是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。 获取锁的线程一直处于活跃状态,但是并没有执行任何有效的任务,使用这种锁会造成busy-waiting。Java如何实现自旋锁?下面是个简单的例子:public class SpinLock { priva...转载 2018-10-25 22:20:41 · 21910 阅读 · 7 评论 -
线程间的通信wait与notify
wait()方法wait()方法使得当前线程必须要等待,等到另外一个线程调用notify()或者notifyAll()方法。当前的线程必须拥有当前对象的monitor,也即lock,就是锁。线程调用wait()方法,释放它对锁的拥有权,然后等待另外的线程来通知它(通知的方式是notify()或者notifyAll() 方法),这样它才能重新获得锁的拥有权和恢复执行。要确保调用wai...原创 2018-10-31 22:48:09 · 1195 阅读 · 0 评论 -
synchronized的底层优化
Synchronized底层是通过对象内部的一个叫做监视器锁(monitor)来实现的。但是监视器锁本质又是依赖于底层的操作系统的Mutex Lock来实现的。而操作系统实现线程之间的切换这就需要从用户态转换到核心态,这个成本非常高,状态之间的转换需要相对比较长的时间,这就是为什么Synchronized效率低的原因。因此,这种依赖于操作系统Mutex Lock所实现的锁我们称之为“重量级锁”。J...转载 2018-11-06 23:25:27 · 1117 阅读 · 0 评论 -
ReentrantLock原理
ReentrantLock主要利用CAS+AQS队列来实现。它支持公平锁和非公平锁,两者的实现类似。CAS:Compare and Swap,比较并交换。CAS有3个操作数:内存值V、预期值A、要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。该操作是一个原子操作,被广泛的应用在Java的底层实现中。在Java中,CAS主要是由sun.misc.Unsafe...转载 2018-11-04 20:18:23 · 75015 阅读 · 22 评论 -
java定时器之Timer使用与原理分析
Timer和TimerTaskTimer是jdk中提供的一个定时器工具,使用的时候会在主线程之外起一个单独的线程执行指定的计划任务,可以指定执行一次或者反复执行多次。TimerTask是一个实现了Runnable接口的抽象类,代表一个可以被Timer执行的任务。【使用举例】【schedule(TimerTask task, long delay) 延迟 delay 毫秒 执行】...原创 2018-11-07 16:10:15 · 20999 阅读 · 2 评论 -
多线程设计模式:Master-Worker模式
Master-Worker是常用的并行计算模式。它的核心思想是系统由两类进程协作工作:Master进程和Worker进程。Master负责接收和分配任务,Worker负责处理子任务。当各个Worker子进程处理完成后,会将结果返回给Master,由Master作归纳总结。其好处就是能将一个大任务分解成若干个小任务,并行执行,从而提高系统的吞吐量。处理过程如下图所示:Master进程为主要进...转载 2018-11-21 22:31:19 · 1176 阅读 · 0 评论 -
多线程复习笔记之一【关键属性与常用关键字概述】
1、并发和并行的区别?并发可以发生在一个或多个CPU,同时处理多个任务,多个任务之间可以进行切换执行;并行只能发生在多核CPU,一核对应一个任务同时运行2、线程和进程之间的区别?a) 一个程序至少有一个进程,一个进程至少有个线程b) 进程在执行过程中拥有独立的内存单元,线程之间的内存却是共享的c) 线程不能独立运行,必须依赖进程举个例子:我们执行一个Main方法,里面其...原创 2018-12-15 17:47:40 · 474 阅读 · 0 评论 -
多线程复习笔记之二【线程间的通信】
Object.wait:释放锁,当时代码不会往下继续执行,需要等待notify通知,wait(1000)超过1秒自动唤醒Object.notify:不释放锁,需要等到同步代码块执行完毕,如果没有wait线程,notify命令将被忽略。condition如果有多个线程处于等待状态,我想唤醒指定的一个线程,Object.notify是唤醒随机一个是无法实现的。condition实现过程如下...原创 2018-12-15 17:53:51 · 416 阅读 · 0 评论 -
多线程复习笔记之三【多线程中的Lock使用】
Lock1、getHoldCount()查询当前线程保持此锁锁定的个数,也就是调用lock方法的次数2、int getQueueLength返回正等待此锁定的线程估计数,例如有5个线程,1个线程首先执行await,那么调用getQueueLength返回43、int getWaitQueueLength(Condition condition)返回等待与次锁定相关的给定条件...原创 2018-12-16 23:00:59 · 1468 阅读 · 0 评论 -
Java线程并发中的锁——Lock(上)
Lock接口锁是用来控制多个线程访问共享资源的方式,一般来说,一个锁能够防止多个线程同时访问共享资源(但是有些锁可以允许多个线程并发的访问共享资源,比如读写锁)。在Lock接口出现之前,Java程序是靠synchronized关键字实现锁功能的,而Java SE 5之后,并发包中新增了Lock接口(以及相关实现类)用来实现锁功能,它提供了与synchronized关键字类似的同步功能,只是在使用时需原创 2017-05-19 18:17:11 · 2050 阅读 · 0 评论 -
线程池原理详解与Java代码示例
为什么使用线程池对于服务端的程序,经常面对的是客户端传入的短小(执行时间短、工作内容较为单一)任务,需要服务端快速处理并返回结果。如果服务端每次接受到一个任务,创建一个线程,然后进行执行,这在原型阶段是个不错的选择,但是面对成千上万的任务递交进服务器时,如果还是采用一个任务一个线程的方式,那么将会创建数以万记的线程,这不是一个好的选择。因为这会使操作系统频繁的进行线程上下文切换,无故增加系统的负载,原创 2017-05-18 18:13:45 · 950 阅读 · 1 评论 -
Java中volatile关键字的作用
在Java内存模型中,有main memory(主内存)还每个线程各自的线程内存memory(例如:寄存器)。为了性能一个线程会在自己memory中保持要访问变量的副本。这样就会出现同一个变量在某一个时刻一个线程内存中的值和其他线程内存或者主内存中的值不一致。 一个变量声明为volatile,就意味着这个变量随时会被其他线程修改,因此不能将他cahe在线程memory中,即:不会再memory中保原创 2015-05-07 22:39:54 · 1872 阅读 · 0 评论 -
史上最全synchronized用法详解
Java中synchronized关键字用于代码的同步执行,他可以修饰代码块、方法、this、Object.class,能够保证在多线程环境中只有线程执行。synchronized作用范围越小并发能力越强,下面我们就各种场景来详解举例说明。多个synchronized(this)代码块并发执行当一个线程访问类中的synchronized(this)的代码块时,该类中的其他synchronized(t原创 2017-05-11 18:00:43 · 3556 阅读 · 0 评论 -
深入synchronized原理详解
synchronized作用在方法上时,锁住的便是对象实例(this);当作用在静态方法时锁住的便是对象对应的Class实例,因为Class数据存在于永久代,因此静态方法锁相当于该类的一个全局锁;当synchronized作用于某一个对象实例时,锁住的便是对应的代码块。在HotSpot JVM实现中,锁有个专门的名字:对象监视器(monitor)。 synchronized就是针对内存区块原创 2017-05-12 12:34:28 · 741 阅读 · 1 评论 -
Java并发中的ConcurrentLinkedQueue源码分析
本文中多次提到CAS算法,先做个CAS算法的简单描述CAS(非阻塞算法)说明CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。 ConcurrentLinkedQueue是一种线程安全的队列。他是使用非阻塞算法(CAS)来实现线程安全的。ConcurrentLinkedQueue是一个基于链接节点的无界线程安全队列, 它原创 2017-05-23 21:42:44 · 2972 阅读 · 2 评论 -
深入剖析Sleep、wait、notify、notifyAll、yield、join、Interrupt
sleep原理sleep是Thread类中的静态方法,首先看下sleep的源码/** * Causes the currently executing thread to sleep (temporarily cease * execution) for the specified number of milliseconds, subject to * the pre原创 2017-05-13 11:14:46 · 1865 阅读 · 0 评论 -
Java多线程的上下文切换
对于上下文切换不同的操作系统模式也不尽相同,这里我们只讨论Unix系统,在我之前的文章中提到过windows的抢占式,这里就不在赘述。 无论是单核还是多核CPU都是支持多线程代码的,CPU通过给每个线程分配CPU时间片来实这个机制。时间片是CPU分配给各个线程的时间,因为时间片非常短,所以CPU通过不停地切换线程执行,让我们感觉多个线程是同时执行的,时间片一般是几十毫秒(ms) CPU通过原创 2017-05-13 18:26:18 · 7251 阅读 · 3 评论 -
Java多线程死锁与资源限制详解
锁是个非常有用的工具,运用场景非常多,因为它使用起来非常简单,而且易于理解。但同时它也会带来一些困扰,那就是可能会引起死锁,一旦产生死锁,就会造成系统功能不可用。死锁的概念那什么是死锁呢?所谓死锁: 是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程原创 2017-05-13 21:46:54 · 1723 阅读 · 0 评论 -
Java多线程volatile详解
volatile定义Java编程语言允许线程访问共享变量,为了确保共享变量能被准确和一致地更新,线程应该确保通过排他锁单独获得这个变量。Java语言提供了volatile,在某些情况下比锁要更加方便。如果一个字段被声明成volatile,Java线程内存模型确保所有线程看到这个变量的值是一致的。volatile的作用先让我们说说volatile关键字的作用。它在多处理器开发中保证了共享变量的“可见性原创 2017-05-14 11:06:31 · 6035 阅读 · 1 评论 -
Java中的常用阻塞队列源码分析
定义支持阻塞的插入方法:意思是当队列满时,队列会阻塞插入元素的线程,直到队列不满。支持阻塞的移除方法:意思是在队列为空时,获取元素的线程会等待队列变为非空。 阻塞队列常用于生产者和消费者的场景,生产者是向队列里添加元素的线程,消费者是从队列里取元素的线程。阻塞队列就是生产者用来存放元素、消费者用来获取元素的容器。ArrayBlockingQueue由数组组成的无界阻塞队列。 一个建立在数组之上被原创 2017-05-24 21:46:25 · 2852 阅读 · 0 评论 -
Java多线程中的内存模型
内存模型在Java中,所有实例域、静态域和数组元素都存储在堆内存中,堆内存在线程之间共享。局部变量(Local Variables),方法定义参数(Java语言规范称之为Formal Method Parameters)和异常处理器参数(ExceptionHandler Parameters)不会在线程之间共享,它们不会有内存可见性问题,也不受内存模型的影响。 Java线程之间的通信由Jav原创 2017-05-14 19:35:19 · 2561 阅读 · 0 评论 -
Java线程池(ThreadPoolExecutor)原理分析与使用
在我们的开发中“池”的概念并不罕见,有数据库连接池、线程池、对象池、常量池等等。下面我们主要针对线程池来一步一步揭开线程池的面纱。使用线程池的好处1、降低资源消耗 可以重复利用已创建的线程降低线程创建和销毁造成的消耗。 2、提高响应速度 当任务到达时,任务可以不需要等到线程创建就能立即执行。 3、提高线程的可管理性 线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性原创 2017-05-25 21:52:32 · 28406 阅读 · 7 评论 -
Java多线程并发中的双重检查锁定与延迟初始化
双重检查锁定与延迟初始化在Java多线程程序中,有时候需要采用延迟初始化来降低初始化类和创建对象的开销。双重检查锁定是常见的延迟初始化技术。 下面我们看一个非线程安全的延迟初始化对象的例子:public class Singleton { private static Singleton instance; public static Singleton getInstance()原创 2017-05-15 18:18:44 · 1159 阅读 · 2 评论 -
ThreadLocal详解
ThreadLocal,即线程变量,是一个以ThreadLocal对象为键、任意对象为值的存储结构。这个结构被附带在线程上,也就是说一个线程可以根据一个ThreadLocal对象查询到绑定在这个线程上的一个值。ThreadLocal源码分析我们看下ThreadLocal几个关键方法get()/** * Returns the value in the current thread's c原创 2017-05-16 18:30:23 · 876 阅读 · 0 评论 -
Java线程Executor框架详解与使用
在HotSpot VM的线程模型中,Java线程被一对一映射为本地操作系统线程。Java线程启动时会创建一个本地操作系统线程;当该Java线程终止时,这个操作系统线程也会被回收,在JVM中我们可以通过-Xss设置每个线程的大小。操作系统会调度所有线程并将它们分配给可用的CPU。 在上层,Java多线程程序通常把应用分解为若干个任务,然后使用用户级的调度器(Executor框架)将这些任务映射为固定原创 2017-05-26 22:55:29 · 9723 阅读 · 1 评论 -
Java多线程中FutureTask详解与正式环境问题定位
通过FutureTask的源码我们可以看到FuturenTask类实现了RunnableFuture接口,继承了Runnable和Future接口。 public class FutureTask implements RunnableFuture public interface RunnableFuture extends Runnable, Future FutureTask可以交给E原创 2017-05-27 18:51:00 · 2515 阅读 · 0 评论 -
数据库连接池原理详解与自定义连接池实现
实现原理数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中,这些数据库连接的数量是由最小数据库连接数制约。无论这些数据库连接是否被使用,连接池都将一直保证至少拥有这么多的连接数量。连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数,当应用程序向连接池请求的连接数超过最大连接数量时,这些请求将被加入到等待队列中。连接池基本的思想是在系统初始化的时候,将数据库连接作为对象存储在内存原创 2017-05-17 18:18:54 · 27037 阅读 · 7 评论 -
多线程复习笔记之四【多线程中的异常】
在一个线程组中如果其中一个线程执行报错并不影响其他线程的继续执行,例如:package com.fyw.thread.lock.exception;public class MyThread extends Thread { private String num; public MyThread(ThreadGroup group,String name,String num) ...原创 2018-12-16 23:54:17 · 1133 阅读 · 1 评论