线程阻塞

JDK源码那些事儿之SynchronousQueue下篇

☆樱花仙子☆ 提交于 2020-04-02 14:07:37
之前一篇文章已经讲解了阻塞队列SynchronousQueue的大部分内容,其中默认的非公平策略还未说明,本文就紧接上文继续讲解其中的非公平策略下的内部实现,顺便简单说明其涉及到的线程池部分的使用 前言 回顾一下,SynchronousQueue通过两个内部类实现了公平策略和非公平策略的无缓存阻塞队列,每种操作都需要对应的互补操作同时进行才能完成,例如,入队操作必然对应出队操作,在不涉及超时和中断的情况下,必须等待另一个线程进行出队操作,两两匹配才能执行,否则就阻塞等待 之前已经对公平策略下的内部类实现TransferQueue做了详细的说明,今天就非公平策略下的内部实现类TransferStack进行说明 TransferStack 不同于公平策略下的操作,只有一种状态需要注意: 取消操作(被外部中断或者超时):match == this; SNode SNode基于栈的节点实现,变量与QNode有些不同,其中match在两个操作匹配上之后可以通过这个变量找到其匹配的节点,节点类型mode在使用上也有所不同,下面使用到时会进行说明,其他参数可参考TransferQueue的QNode说明 static final class SNode { // next指向栈中下一个元素 volatile SNode next; // next node in stack //

多线程(4)线程生命周期

寵の児 提交于 2020-04-02 14:00:12
多线程有六个状态 1.New(新创建) : 已创建但是还没有启动的新线程, new Thread()还没执行start() 2.Runnable( 可运行) :, 包括start()后等待运行和拿到资源运行中 3.Blocked(被阻塞) : synchronized修饰的代码没有拿到锁(monitor)陷入的等待状态。注意必须是synchronized修饰,其他的锁不是 4.Waiting(等待) : Object.wait(), Thread.join(), LockSupport.park()这三个没有timeout参数的方法会让线程进入等待状态. Object.notify()或者Object.notifyAll(), 等待join方法所运行的线程执行完毕, LockSupport.unpark() 会让等待的线程进入可运行状态 Lock.lock进入的是waiting状态而不是Blocked waiting和blocked的区别根本原因是“是不是内置锁”。Lock不是Java语言支持的锁,是JDK包提供的,而synchronized是关键字级别是,它们不一样。 5.Timed Waiting(计时等待) : 等待的那三个方法带了时间参数, 超时会自动唤醒也可以被notify等唤醒 6.Terminated(被终止) :run方法正常执行完,run被未捕获的异常终止 注意:

CountDownLatch、CyclicBarrier和Semaphore

不羁的心 提交于 2020-04-02 09:37:54
一.CountDownLatch用法 CountDownLatch类位于java.util.concurrent包下,利用它可以实现类似计数器的功能。比如有一个任务A,它要等待其他4个任务执行完毕之后才能执行,此时就可以利用CountDownLatch来实现这种功能了。 CountDownLatch的构造函数接收一个int类型的参数作为计数器,如果你想等待N个点完成,这里就传入N。 当我们调用一次CountDownLatch的countDown方法时,N就会减1,CountDownLatch的await会阻塞当前线程,直到N变成零。由于countDown方法可以用在任何地方,所以这里说的N个点,可以是N个线程,也可以是1个线程里的N个执行步骤。用在多个线程时,你只需要把这个CountDownLatch的引用传递到线程里。 其他方法 如果有某个解析sheet的线程处理的比较慢,我们不可能让主线程一直等待,所以我们可以使用另外一个带指定时间的await方法,await(long time, TimeUnit unit): 这个方法等待特定时间后,就会不再阻塞当前线程。join也有类似的方法。 注意:计数器必须大于等于0,只是等于0时候,计数器就是零,调用await方法时不会阻塞当前线程。CountDownLatch不可能重新初始化或者修改CountDownLatch对象的内部计数器的值

线程、进程、死锁

别来无恙 提交于 2020-04-01 07:43:16
题目转自http://blog.csdn.net/morewindows/article/details/7392749 第一题:线程的基本概念、线程的基本状态及状态之间的关系? 线程,有时称为轻量级进程,是CPU使用的基本单元;它由线程ID、程序计数器、寄存器集合和堆栈组成。它与属于同一进程的其他线程共享其代码段、数据段和其他操作系统资源(如打开文件和信号)。 线程有四种状态:新生状态、可运行状态、被阻塞状态、死亡状态。状态之间的转换如下图所示: 第二题:线程与进程的区别? 1、 线程是进程的一部分,所以线程有的时候被称为是轻权进程或者轻量级进程。 2、 一个没有线程的进程是可以被看作单线程的,如果一个进程内拥有多个进程,进程的执行过程不是一条线(线程)的,而是多条线(线程)共同完成的。 3、 系统在运行的时候会为每个进程分配不同的内存区域,但是不会为线程分配内存(线程所使用的资源是它所属的进程的资源),线程组只能共享资源。那就是说,出了CPU之外(线程在运行的时候要占用CPU资源),计算机内部的软硬件资源的分配与线程无关,线程只能共享它所属进程的资源。 4、 与进程的控制表PCB相似,线程也有自己的控制表TCB,但是TCB中所保存的线程状态比PCB表中少多了。 5、 进程是系统所有资源分配时候的一个基本单位,拥有一个完整的虚拟空间地址,并不依赖线程而独立存在。 第三题

Java-----多线程sleep(),join(),interrupt(),wait(),notify()的作用

送分小仙女□ 提交于 2020-04-01 04:30:15
关于Java多线程知识可以看看《Thinking in Java 》中的多线程部分和《Java网络编程》中第5章多线程的部分 以下是参考<<Java多线程模式>>的 1. sleep() & interrupt() 线程A正在使用sleep()暂停着: Thread.sleep(100000); 如果要取消他的等待状态,可以在正在执行的线程里(比如这里是B)调用 a.interrupt(); 令线程A放弃睡眠操作,这里a是线程A对应到的Thread实例 执行interrupt()时,并不需要获取Thread实例的锁定.任何线程在任何时刻,都可以调用其他线程interrupt().当sleep中的线程被调用interrupt()时,就会放弃暂停的状态.并抛出InterruptedException.丢出异常的,是A线程. 2. wait() & interrupt() 线程A调用了wait()进入了等待状态,也可以用interrupt()取消. 不过这时候要小心锁定的问题.线程在进入等待区,会把锁定解除,当对等待中的线程调用interrupt()时(注意是等待的线程调用其自己的interrupt()),会先重新获取锁定,再抛出异常.在获取锁定之前,是无法抛出异常的. 3. join() & interrupt() 当线程以join()等待其他线程结束时,一样可以使用interrupt

CAS -- ABA问题的解决方案

点点圈 提交于 2020-03-31 13:05:55
CAS:Compare and Swap, 翻译成比较并交换。 java.util.concurrent包中借助CAS实现了区别于synchronized同步锁的一种乐观锁。 其原理是CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。 我们现在来说什么是ABA问题。假设内存中有一个值为A的变量,存储在地址V中。 此时有三个线程想使用CAS的方式更新这个变量的值,每个线程的执行时间有略微偏差。线程1和线程2已经获取当前值,线程3还未获取当前值。 接下来,线程1先一步执行成功,把当前值成功从A更新为B;同时线程2因为某种原因???被阻塞住,没有做更新操作;线程3在线程1更新之后,获取了当前值B。 为什么线程3又反过来操作???是自旋吗??? 在之后,线程2仍然处于阻塞状态,线程3继续执行,成功把当前值从B更新成了A。 最后,线程2终于恢复了运行状态,由于阻塞之前已经获得了“当前值A”,并且经过compare检测,内存地址V中的实际值也是A,所以成功把变量值A更新成了B。 个人见解: 不是说一定出现ABA情况,是说有出现这种情况的可能性。也就是举一个特例来说明问题的可能性??? 看起来这个例子没啥问题,但如果结合实际,就可以发现它的问题所在。 我们假设一个提款机的例子。假设有一个遵循CAS原理的提款机

爬虫数据结构

陌路散爱 提交于 2020-03-31 08:35:12
一、多任务简介 1、为什么要使用多任务爬虫? 在大量的url需要请求时,单线程/单进程去爬取,速度太慢,此时cpu不工作,浪费cpu资源。 爬取与写入文件分离,可以规避io操作,增加爬取速度,充分利用cpu。 2、多任务分类 进程:进程是操作资源分配的最小单位,一个运行的程序,至少包括一个进程,进程之间数据不能共享。(利用多核) 线程:线程是cpu调度的最小单位,一个进程中至少含有一个线程,线程中数据是共享的,如果多个线程操作同一个对象时,需要考虑数据安全问题。(爬虫中最常用) 协程:协程位于线程内部,如果一个线程中运行的代码,遇到IO操作时,切换到线程其他代码执行(最大程度的规避IO操作) 2、如何提高程序的运行速度 1、提高CPU的利用率 假如我们的程序有只有一个线程,CPU就只处理这一个线程。如果在程序中遇到IO操作。此时CPU就不工作了。休息的这段时间,就浪费了CPU的资源。 若我们的程序是多线程的,CPU会在这多个任务之间切换,如果其中一个线程阻塞了,CPU不会休息,会处理其他线程。 2、增加CPU数量 一个CPU同一时间只能护理一个任务,若我们增加CPU数量,那么多个CPU处理多个任务,也会提升程序的运行速度,例如使用多进程。 二、python中的threading模块(开启多线程) cpython解释器下的 python中没有真正的多线程

day09 并发编程

允我心安 提交于 2020-03-31 08:06:11
一. 目录   1.进程的概念和两种创建方式   2.多进程爬虫   3.守护进程   4.进程队列   5.进程队列简单应用(实现数据共享)   6.线程的两种创建方式   7.线程和进程的效率对比   8.线程共享统一进程的数据   9.死锁现象   10.线程队列的三种应用   11.多线程执行计算密集型任务   12. 线程池和进程池   13. 回调函数   14.守护线程   15. 协程   16.GlL 全局解释器锁 二. 内容 一.进程的概念和两种创建方式 专业词描述: 操作系统的两大作用 1.把硬件丑陋复杂的接口隐藏起来,为应用程序提供良好的接口 2.管理,调度进程,并且把进程之间对硬件的竞争变的有序化多道技术: 1.产生背景:为了实现单cpu下的并发效果 2.分为两个部分 1.空间上的复用(必须实现硬件层面的隔离) 2.时间上的复用(复用的是cpu的时间片) 什么时候切换? 1.正在执行的任务遇到阻塞 2.正在执行的任务运行时间过程(系统控制的)进程:正在运行的一个过程,一个任务,由操作系统负责调度,由cpu负责 执行程序:程序员写的代码并发:伪并行,单核+多道并行:只有多核才能实现真正的并行同步:一个进程在执行某个任务时,另外一个进程必须等待其执行完毕才能往下走异步:一个进程在执行某个任务时,另外一个进程无须等待其执行完毕,继续往下走进程的创建: 1

07:线程安全-可见性问题

心不动则不痛 提交于 2020-03-30 22:57:40
由指令重排序引起的可见性问题: public class Test { // 如果运行时加上 -server 下面的代码就变成了死循环,没有加就正常运行。(运行器的编译优化只有在服务器模式下才执行) // 通过设置JVM参数,打印出JIT(即时编译)编译的内容(这里说的编译不是指class文件的编译,而是指未变级别的编译) private boolean flag = true; // -server -Djava.compiler=NONE 参数可以关闭jit优化。 // 在多线程中,由于指令重排序引起的线程可见性问题。 public static void main(String[] args) throws IOException, InterruptedException { Test demo1 = new Test(); new Thread(new Runnable() { @Override public void run() { int i = 0; // class文件在运行时jit编译成为汇编指令,汇编指令出现了重排序。 /* // 重排序后的逻辑。因为while语句里面需要一直判断flag。所以jvm优化为外层使用if判断一次。 if(demo1.flag){ while (true){ i++; } } hot code : 热点代码。

06:线程池

六月ゝ 毕业季﹏ 提交于 2020-03-30 22:48:15
1:线程池原理-基本概念: 1:线程池管理器:用户管理线程池。包括创建线程池、销毁线程池,添加新任务等。 2:工作线程:工作线程就是线程池中实际工作的线程。没有任务时:处于等待状态,有任务时:可以循环的执行任务。 3:任务接口:每个任务都需要实现的接口。规范了任务的输入、输出等。 4:任务队列:任务太多时,超过了线程池处理能力。将待处理的任务放到等待队列中。 2:线程池接口和实现类: 1:接口:Executor:最上层的接口:定义了执行任务的方法:executor() 2:接口:ExecutorService:继承了Executor接口,扩展了Callable,Future,关闭方法。 3:接口:ScheduledExecutorService:继承了ExecutorService,怎加了定时任务相关的方法。 4:实现类:ThreadPoolExecutor:标准的线程池实现。但是比较基础。 5:实现类:ScheduledThreadPoolExecutor:继承了ThreadPoolExecutor,实现了ScheduledExecutorService。也就是说:在标准的线程池类基础上怎加了定时任务。 3:ThreadPoolExecutorc测试: /** * 1:核心线程数量5,最大数量10,无界队列,超出核心线程数量的线程存活时间5秒。 */ //