线程阻塞

java

守給你的承諾、 提交于 2020-03-17 13:24:28
1、CAS Conmpare And Swap比较和交换,主要用于多个线程对共享内存的变量(全局变量)操作时的线程安全问题。它将内存位置的内容与给定值进行比较,只有在相同的情况下,将该内存位置的内容修改为新的给定值。这是作为单个原子操作完成的。 一个 CAS 涉及到以下操作 我们假设内存中的原数据V,旧的预期值A(线程从共享内存中取出的数据),需要修改的新值B。 比较 A 与 V 是否相等。(比较) 如果比较相等,将 B 写入 V。(交换) 返回操作是否成功。 当多个线程同时对某个资源进行CAS操作,只能有一个线程操作成功,但是并不会阻塞其他线程,其他线程只会收到操作失败的信号。可见 CAS其实是一个乐观锁。 下图中,主存中保存V值,线程中要使用V值要先从主存中读取V值到线程的工作内存A中,然后计算后变成B值,最后再把B值写回到内存V值中。多个线程共用V值都是如此操作。CAS的核心是在将B值写入到V之前要比较A值和V值是否相同,如果不相同证明此时V值已经被其他线程改变,重新将V值赋给A,并重新计算得到B,如果相同,则将B值赋给V。 ABA 问题 CAS 由三个步骤组成,分别是“读取->比较->写回”。 考虑这样一种情况,线程1和线程2同时执行 CAS 逻辑,两个线程的执行顺序如下: 时刻1:线程1执行读取操作,获取原值 A,然后线程被切换走 时刻2:线程2执行完成 CAS

zookeeper实现分布式锁

╄→尐↘猪︶ㄣ 提交于 2020-03-17 11:53:15
思考:分布式锁实现的逻辑 1.争抢锁,只有一个线程可以获得锁。 2.获得锁的线程挂了,产生死锁。解决:使用临时节点(伴随客户端的session,session删除时临时节点也会删除)。 3.获得锁的线程执行成功,释放锁。 4.上面两点,锁被删除或者释放,其他线程如何知道。 (1.主动轮询,弊端:延迟,压力 。 2.watch,解决延迟问题,弊端:压力) 5.sequence(序列节点) + watch:watch前一个,最小的获得锁,一旦最小的释放锁,只给watch他的那个发事件回调。 public class WatchCallBack implements Watcher ,AsyncCallback.StringCallback ,AsyncCallback.Children2Callback ,AsyncCallback.StatCallback { ZooKeeper zk ; String threadName; CountDownLatch cc = new CountDownLatch(1); String pathName; public String getPathName() { return pathName; } public void setPathName(String pathName) { this.pathName = pathName; }

Java NIO概述

故事扮演 提交于 2020-03-17 11:44:04
传统的输入输出流都是阻塞的输入输出。举个列子:当用传统的流进行数据输入时,如果流中没有数据,它会阻塞当前线程往下执行,等到从流中读到数据为止。另外传统的输入输出流每次处理的是一个字节或一个字符,通常效率不是很高。从JDK 1.4开始 Java提供了NIO功能,可以代替传统的输入输出功能,在效率上也有很大提升。 标准的IO基于字节流和字符流进行操作的,而NIO是基于通道(Channel)和缓冲区(Buffer)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中(双向操作)。NIO可以使用非阻塞模式。 NIO概述 NIO在处理文件时会将文件的一段区域直接映射到内存中,这样访问文件时就可以像访问内存一样,比传统的输入输出要快很多 。主要的实现类都在java.nio下面。 Channe l和 Buffer 是NIO中两个核心的概念。Channel的概念和传统的InputStram和OutputStream对标,最大的区别是Channel提供了一个map()方法将文件的块数据映射到内存中。可以面向一大块数据进行处理。Buffer可以理解成缓冲,其本质是一个数组。从Channel中读出来的数据要先存在Buffer中,要写到Channel中的数据也要先放到Buffer中。 另外,NIO还提供了将Unicode字符串映射成字节序列的Charset类

线程同步synchronized

六眼飞鱼酱① 提交于 2020-03-17 11:41:01
同步条件:等待池序列,锁机制。 由于同一进程的多个线程共享同一块存储空间,在带来方便的同时,也带来了访问冲突的问题。为了保证数据在方法中被访问时的正确性,在访问时加入锁机制(synchronized),当一个线程获得对象的排它锁,独占资源,其他线程必须等待,使用后释放锁即可。存在以下问题: 一个线程持有锁会导致其它所有需要此锁的我程挂起; 在多线程竞争下,加锁、释放锁会导致比较多的上下文切换和调度延时,引起性能问题: 如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级倒置,引起性能问题。 可以 修饰方法或者代码块 ,确保多个线程在同一时刻,只能有一个线程处理方法或者是同步块,Synchronized修饰的方法或者代码块相当于并发中的临界区,在同一时刻JVM只允许一个线程进入执行。 保证线程对访问变量的可见性,有序性,原子性 。 修饰普通方法 修饰静态方法 修饰代码块 通过synchronized关键字来处理统计1秒钟count++的次数 public class SynchronizedDemo { private static boolean flag = true; public static void main(String[] args) { Thread thread = new Thread(new Runnable() { @Override public

JAVA并发编程-线程间协作(Object监视器方法与Condition)

二次信任 提交于 2020-03-17 11:21:32
某厂面试归来,发现自己落伍了!>>> 原文地址: http://blog.csdn.net/zhshulin/article/details/50762465 下面只是简单的介绍一下,具体代码可以看我分享的代码,注释都有 说到线程间协作,不得不提到经典的 生产者与消费者模型 :有一个商品队列,生产者想队列中添加商品,消费者取出队列中的商品;显然,如果队列为空,消费者应该等待生产者产生商品才能消费;如果队列满了,生产者需要等待消费者消费之后才能生产商品。队列就是这个模型中的临界资源,当队列为空时,而消费者获得了该对象的锁,如果不释放,那么生产者无法获得对象锁,而消费者无法消费对象,就进入了死锁状态;反之队列满时,生产者不释放对象锁也会造成死锁。这是我们不希望看到的,所以就有了线程间协作来解决这个问题。 其实说到生产者与消费者模型,我们不能简单的知道怎么实现,而是需要知这种模型的使用场景:主要是为了复用和解耦, 常见的消息框架(非常经典的一种生产者消费者模型的使用场景) ActiveMQ 。发送端和接收端用Topic进行关联。 JAVA语言中,如何实现线程间协作呢?比较常见的方法就是利用Object.wait(),Object.notify()和Condition。 先看看这几个方法究竟有什么作用?为什么利用它们就可以实现线程间协作了呢? 首先分析一下wait()/notify()

Netty题目总结

蓝咒 提交于 2020-03-17 08:59:05
1.BIO、NIO 和 AIO 的区别? BIO:一个连接一个线程,客户端有连接请求时服务器端就需要启动一个线程进行处理。线 程开销大。 伪异步 IO:将请求连接放入线程池,一对多,但线程还是很宝贵的资源。 NIO:一个请求一个线程,但客户端发送的连接请求都会注册到多路复用器上,多路复用 器轮询到连接有 I/O 请求时才启动一个线程进行处理。 AIO:一个有效请求一个线程,客户端的 I/O 请求都是由 OS 先完成了再通知服务器应用去 启动线程进行处理, BIO 是面向流的,NIO 是面向缓冲区的;BIO 的各种流是阻塞的。而 NIO 是非阻塞的;BIO 的 Stream 是单向的,而 NIO 的 channel 是双向的。 NIO的特点:事件驱动模型、单线程处理多任务、非阻塞 I/O,I/O 读写不再阻塞,而是返 回 0、基于 block 的传输比基于流的传输更高效、更高级的 IO 函数 zero-copy、IO 多路复用 大大提高了 Java 网络应用的可伸缩性和实用性。基于 Reactor 线程模型。 在 Reactor 模式中,事件分发器等待某个事件或者可应用或个操作的状态发生,事件分发 器就把这个事件传给事先注册的事件处理函数或者回调函数,由后者来做实际的读写操 作。如在 Reactor 中实现读:注册读就绪事件和相应的事件处理器、事件分发器等待事 件、事件到来

走进 Java Volatile 关键字

核能气质少年 提交于 2020-03-17 07:50:43
Java Volatile 关键字是一种轻量级的数据一致性保障机制,之所以说是轻量级的是因为 volatile 不具备原子性,它对数据一致性的保障体现在对修改过的数据进行读取的场景下(也就是数据的可见性)。比起对读操作使用互斥锁, volatile 是一种很高效的方式。因为 volatile 不会涉及到线程的上下文切换,以及操作系统对线程执行的调度运算。同时 volidate 关键字的另一个功能是解决“指令重排序问题”。 Volatile 可见性承诺 Java volatile关键字保证了跨线程更改线程间共享变量的可见性。这可能听起来有点抽象,让我们详细说明一下。 在多线程应用程序中,线程对 non-volatile 变量进行操作,出于性能原因,每个线程在处理变量时,可以将它们从主内存复制到CPU缓存中。如果你的计算机包含一个以上的CPU,每个线程可以在不同的CPU上运行。这意味着,每个线程可以将同一个变量复制到不同CPU的CPU缓存中。这就和计算机的组成和工作原理息息相关了,之所以在每一个 CPU 中都含有缓存模块是因为出于性能考虑。因为 CPU 的执行速度要比内存(这里的内存指的是 Main Memory)快很多,因为 CPU 要对数据进行读、写的操作,如果每次都和内存进行交互那么 CPU 在等待 I/O 这个过程中就消耗了大量时间

Python之线程

心已入冬 提交于 2020-03-17 06:34:56
为什么需要线程 进程有很多优点,它提供了多道编程,让我们感觉我们每个人都拥有自己的CPU和其他资源,可以提高计算机的利用率。很多人就不理解了,既然进程这么优秀,为什么还要线程呢?其实,仔细观察就会发现进程还是有很多缺陷的,主要体现在两点上: 进程只能在一个时间干一件事,如果想同时干两件事或多件事,进程就无能为力了。 进程在执行的过程中如果阻塞,例如等待输入,整个进程就会挂起,即使进程中有些工作不依赖于输入的数据,也将无法执行。 什么是线程 线程,有时被称为轻量进程(Lightweight Process,LWP),是程序执行流的最小单元,也是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。 线程与进程的区别: 根本区别:进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位 在开销方面:每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小。 所处环境:在操作系统中能同时运行多个进程(程序);而在同一个进程(程序)中有多个线程同时执行(通过CPU调度,在每个时间片中只有一个线程执行)

IO的四种模型

折月煮酒 提交于 2020-03-17 02:19:45
Nio Io读写,读写都会涉及底层的read和write的使用。Read把内核缓冲区的内容复制到进程缓冲区。 外部设备的直接读写会涉及到系统的中断,发生系统中断时,会保存之前的进程和状态信息,等中断结束还要恢复之前的。 BIO(blocking io) 从线程发出读请求,线程会一直处于阻塞模式,缺点:会为每个连接配备一个线程,在高并发的场景下,需要大量的线程来维护网络连接,内存和线程切换消耗大。 NIO(None Blocking IO) 在内核缓冲区没有数据时,用户发起请求会立即返回, 为了读取最终的数据,用户IO会不断地发起IO调用 直到数据完整后,用户线程阻塞,直到用户线程获取到数据 缺点:轮询会消耗cpu的大量的时间。 IO Multiplexing (1) 进行read操作,就会将目标socket的网络连接提前注册到select/epoll选择器中去(selector)类中 (2) 通过查询的系统调用,就会返回一个就绪的socket列表,,用户进程调用了select,整个线程会被阻塞掉 (3) 获取到列表中的socket后,发起read系统调用,整个线程会被阻塞掉。直到读取到数据。 IO多路复用两种系统的操作:select/epoll 和 IO操作 优点:一个选择器查询线程可以同时监听几万个连接,不必创建和维护大量的线程 缺点:select/epoll是阻塞的

【Linux】线程----线程安全

懵懂的女人 提交于 2020-03-17 00:59:28
线程安全 概念 实现方法 互斥 互斥锁 互斥锁原理 互斥锁操作流程: 举例 死锁 死锁产生的必要条件: 预防死锁 避免死锁 同步 条件变量 条件变量提供的接口功能 例子 问题分析 注意 概念 多个执行流 对 临界资源 进行 争抢访问 ,而不会造成 数据二义性 或者 逻辑混乱 ,称这段争抢访问的过程是线程安全的。 实现方法 线程安全的实现: 同步 :通过 条件判断 ,实现对临界资源访问的时序合理性 互斥 :通过 唯一访问 ,实现对临界资源访问的安全性 互斥 互斥的实现技术: 互斥锁 、 信号量 实现互斥的原理:只要保证 同一时间只有一个执行流能够访问资源 就是互斥 对临界资源进行状态标记:没人访问的时候标记为1,表示可以访问;有人正在访问的时候,就标记为0,表示不可访问;在对 临界资源 进行 访问之前 先 进行状态判断 ,决定是否能够访问,不能访问则使其 休眠 。 互斥锁 互斥锁原理 互斥锁:其实就是一个 计数器 ,只有0/1的计数器,用于标记资源当前的访问状态 1----可访问 0----不可访问 互斥锁想要实现互斥,每个线程在访问临界资源之前都要先访问 同一个互斥锁 (加锁);意味着 互斥锁本身就是一个临界资源 (涉及到计数器的修改,修改过程必须保证安全,如果连自己都保护不了,如何保护他人?) 如果是普通的计数器,则操作步骤为 将mutex的值加载到CPU的一个寄存器