线程阻塞

Java并发编程:volatile关键字解析

*爱你&永不变心* 提交于 2020-04-06 05:23:52
volatile这个关键字可能很多朋友都听说过,或许也都用过。在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果。在Java 5之后,volatile关键字才得以重获生机。   volatile关键字虽然从字面上理解起来比较简单,但是要用好不是一件容易的事情。由于volatile关键字是与Java的内存模型有关的,因此在讲述volatile关键之前,我们先来了解一下与内存模型相关的概念和知识,然后分析了volatile关键字的实现原理,最后给出了几个使用volatile关键字的场景。   以下是本文的目录大纲:   一.内存模型的相关概念   二.并发编程中的三个概念   三.Java内存模型   四..深入剖析volatile关键字   五.使用volatile关键字的场景   若有不正之处请多多谅解,并欢迎批评指正。   请尊重作者劳动成果,转载请标明原文链接:   http://www.cnblogs.com/dolphin0520/p/3920373.html 一.内存模型的相关概念   大家都知道,计算机在执行程序时,每条指令都是在CPU中执行的,而执行指令过程中,势必涉及到数据的读取和写入。由于程序运行过程中的临时数据是存放在主存(物理内存)当中的,这时就存在一个问题,由于CPU执行速度很快

007. J.U.C 之锁的使用

£可爱£侵袭症+ 提交于 2020-04-06 01:53:40
1. Lock API 1. Locks 包类层次结构 2. Lock 接口 方法签名 描述 void lock(); 获取锁(不死不休) boolean tryLock(); 获取锁(浅尝辄止) boolean tryLock(long time, TimeUnit unit) throws InterruptedException; 获取锁(过时不候) void lockInterruptibly() throws InterruptedException; 获取锁(任人摆布) void unlock(); 释放锁 Condition newCondition(); 结论: lock() 最常用,并且线程不会被中断; lockInterruptibly() 方法一般更昂贵,有的 impl 可能没有实现 lockInterruptibly(),只有真的需要效应中断时,才使用,使用之前看看 impl 对该方法的描述。 public class Demo1_GetLock { // 公平锁 // static Lock lock = new ReentrantLock(true); // 非公平锁 static Lock lock = new ReentrantLock(); public static void main(String[] args) throws

原子性,有序性,可见性

纵饮孤独 提交于 2020-04-06 01:01:14
synchronized (原子性 有序性 可见性) volatile (原子性 可见性) 1.volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取;synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。 2.volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的。 3.volatile仅能实现变量的修改可见性,并不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性。 4.volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。 5.volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化。 原子性:所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束 例如:int i = 1; 该语句为原子操作,因为执行这句话后i的值一定是等于1. 反例:int i= 0; i++ ; 其中 i++不是原子操作,在多线程中会有线程安全问题,i++其实分为三个步骤,1. 读取变量i的值;2:对i进行加一的操作;3.将计算后的值再赋值给变量i synchronized :能保证原子操作。1、锁住主内存,2、执行工作内 3、将工作内存写入主内存。4.释放锁

技术大牛详谈如何正确使用 Volatile 变量

旧时模样 提交于 2020-04-05 23:05:26
Java 语言中的 volatile 变量可以被看作是一种 “程度较轻的 synchronized”;与 synchronized 块相比,volatile 变量所需的编码较少,并且运行时开销也较少,但是它所能实现的功能也仅是 synchronized 的一部分。 本文介绍了几种有效使用 volatile 变量的模式,并强调了几种不适合使用 volatile 变量的情形。 锁提供了两种主要特性:互斥(mutual exclusion) 和可见性(visibility)。互斥即一次只允许一个线程持有某个特定的锁,因此可使用该特性实现对共享数据的协调访问协议,这样,一次就只有一个线程能够使用该共享数据。 可见性要更加复杂一些,它必须确保释放锁之前对共享数据做出的更改对于随后获得该锁的另一个线程是可见的 —— 如果没有同步机制提供的这种可见性保证,线程看到的共享变量可能是修改前的值或不一致的值,这将引发许多严重问题。 Volatile 变量 Volatile 变量具有 synchronized 的可见性特性,但是不具备原子特性。这就是说线程能够自动发现 volatile 变量的最新值。 Volatile 变量可用于提供线程安全,但是只能应用于非常有限的一组用例:多个变量之间或者某个变量的当前值与修改后值之间没有约束。因此,单独使用 volatile 还不足以实现计数器

多线程

自作多情 提交于 2020-04-05 18:10:08
进程vs线程: 进程:每个程序被运行加载到内存之后,都会被操作系统作为一个进程,进程是处于运行过程中的程序,是具有独立功能,被操作系统进行资源分配和调度的独立单元。 线程:一个进程里面可以拥有多个线程,线程拥有自己的堆栈,程序计数器和自己的局部变量,但是不拥有系统资源,多个线程共享进程的系统资源。 创建线程的三种方式: 1.继承Thread类创建线程类 继承Thread类,重写run()方法,该run()方法就代表程序需要完成的任务。创建Thread子类的实例,即创建线程对象。然后通过start()方法启动线程。 1 public class MyThread extends Thread { 2 private int count; 3 4 @Override 5 public void run() { 6 7 for (; count < 100; count ++) { 8 System.out.println(getName() + "---" + count); 9 } 10 } 11 12 public static void main(String[] args) { 13 for (int i = 0; i < 100; i++) { 14 System.out.println(Thread.currentThread().getName() + i); 15 if

线程之Semaphore之事例

删除回忆录丶 提交于 2020-04-05 15:59:36
概述 为了提高接口的响应速度,可以使用 ThreadPoolExecutor + Runnable 或者 ThreadPoolExecutor 并发调用 技术来并行执行task。但是ThreadPoolExecutor有个特点,就是当core线程不足以应付请求的时候,会将task加入到队列中。一旦使用队列,那么就可能出现队列爆掉或者队列导致的内存溢出问题。 为了尽快提供接口响应速度,但是又不想使用队列特性的话。可以使用信号量来做到。 Semaphore信号量管理着一组许可,在执行操作时需要首先获得许可,并在使用后释放许可。如果已经没有许可了, acquire方法将一直阻塞,直到有许可。 信号量简单例子 ThreadPoolExecutor中使用信号量 在ThreadPoolExecutor中,我们在定义core线程参数的时候,比如定义为10个,那么使用信号量的时候,初始化参数也设置为10. Semaphore<Integer> sem= new Semaphore<>(10); ThreadPoolExecutor中,如果不想用到队列, 就必须保证线程池中始终只有core线程在工作 。那么当请求太多,core线程处理不过来的时候,用信号量进行阻塞, 保证只有当core线程的某些线程执行完后,阻塞才解开。 这里使用JAVA并发编程一书中的例子来说明信号量的基本用法。 public

Java线程中的锁你掌握了吗?

≡放荡痞女 提交于 2020-04-05 15:46:09
一、同步问题提出 线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏。 例如:两个线程ThreadA、ThreadB都操作同一个对象Foo对象,并修改Foo对象上的数据。 public class Foo { private int x = 100; ​ public int getX() { return x; } ​ public int fix(int y) { x = x - y; return x; } } public class MyRunnable implements Runnable { private Foo foo = new Foo(); ​ public static void main(String[] args) { MyRunnable r = new MyRunnable(); Thread ta = new Thread(r, "Thread-A"); Thread tb = new Thread(r, "Thread-B"); ta.start(); tb.start(); } ​ public void run() { for (int i = 0; i < 3; i++) { this.fix(30); try { Thread.sleep(1); } catch (InterruptedException e) { e

volatile 关键字

拟墨画扇 提交于 2020-04-04 17:53:52
摘抄并用于学习笔记 1. volatile 简介   volatile 是并发编程中另一知识点,与 Synchronized 各领风骚。   synchronized 是阻塞式同步,在线程竞争激烈的情况下会升级成重量级锁。而 volatile 就是 java 虚拟机提供的最轻量级的同步机制。Java 内存模型告诉我们,各个线程会将共享变量从主内存中拷贝到工作内存,然后执行引擎会基于工作内存中的数据进行操作处理。线程在工作内存进行操作后何时会写到主内存中?这个时机对普通变量是没有规定的,而针对 volatile 修饰的变量给 Java 虚拟机特殊的约定,线程对 volatile 变量的修改会立刻被其他线程所感知,即不会出现数据脏读的现象,从而保证数据的“可见性”。   现在我们有了一个大概的印象就是:被 volatile 修饰的变量能够保证每个线程获取该变量时是新值,从而避免出现数据脏读的现象。 2. volatile 实现原理   在生成汇编代码时会在 volatile 修饰的共享变量进行写操作的时候多出 Lock 前缀的指令。   为了提高处理速度,处理器不直接和内存进行通信,而是先将系统内存的数据读到内部缓存(L1,L2 或 其他)后再进行操作,但操作完不知道何时会写到内存。如果对声明了 volatile 的变量进行写操作,JVM 就会向处理器发送一条 Lock 前缀的指令

java多线程

旧城冷巷雨未停 提交于 2020-04-04 06:16:05
1、进程与线程 我们可以在计算机上运行各种计算机软件程序。每一个运行的程序可能包括多个独立运行的线程(Thread)。 线程(Thread)是一份独立运行的程序,有自己专用的运行栈。线程有可能和其他线程共享一些资源,比如,内存,文件,数据库等。 当多个线程同时读写同一份共享资源的时候,可能会引起冲突。这时候,我们需要引入线程“同步”机制,即各位线程之间要有个先来后到,不能一窝蜂挤上去抢作一团。 同步这个词是从英文synchronize(使同时发生)翻译过来的。我也不明白为什么要用这个很容易引起误解的词。既然大家都这么用,咱们也就只好这么将就。 线程同步的真实意思和字面意思恰好相反。线程同步的真实意思,其实是“排队”:几个线程之间要排队,一个一个对共享资源进行操作,而不是同时进行操作 。 因此,关于线程同步,需要牢牢记住的第一点是: 线程同步就是线程排队 。同步就是排队。线程同步的目的就是避免线程“同步”执行。这可真是个无聊的绕口令。 关于线程同步,需要牢牢记住的第二点是 “共享” 这两个字。 只有共享资源的读写访问才需要同步 。如果不是共享资源,那么就根本没有同步的必要。 关于线程同步,需要牢牢记住的第三点是,只有“ 变量 ”才需要同步访问。如果共享的资源是固定不变的,那么就相当于“常量”,线程同时读取常量也不需要同步。至少一个线程修改共享资源,这样的情况下,线程之间就需要同步。

手写线程池

跟風遠走 提交于 2020-04-04 05:41:35
Executors.newSingleThreadExecutor(): 只有一个线程的线程池,因此所有提交的任务是顺序执行 Executors.newCachedThreadPool(): 线程池里有很多线程需要同时执行,老的可用线程将被新的任务触发重新执行, 如果线程超过60秒内没执行,那么将被终止并从池中删除 Executors.newFixedThreadPool(): 拥有固定线程数的线程池,如果没有任务执行,那么线程会一直等待 Executors.newScheduledThreadPool(): 用来调度即将执行的任务的线程池 Executors.newWorkStealingPool(): newWorkStealingPool适合使用在很耗时的操作, 但是newWorkStealingPool不是ThreadPoolExecutor的扩展, 它是新的线程池类ForkJoinPool的扩展,但是都是在统一的一个Executors类中实现, 由于能够合理的使用CPU进行对任务操作(并行操作),所以适合使用在很耗时的任务中 生产环境不使用以上线程池,主要原因是,以上线程池底层使用的LinkedBlockingQueue链表阻塞 队列,这样最大值为21亿,范围过大,会造成OOM异常。 需要使用ThreadPoolExecutor传递7个参数手工实现线程池。