线程的创建与运行 接口Runnable 覆盖run方法 Thread thread = Thread(Runnable r,String name); thread.start(); 线程信息 thread中包含 id name priorty status priorty中包括1到10,1最低,10最高 status状态有6种:new, runnable, blocked, waiting, time waiting 线程中不可控异常处理 非运行时异常,ioexception classnotfoundexception,必须声明throw或捕获 运行时异常,numberformatexception,不需要任何操作
可以看到在构造方法中只是去 new 了一个 Sync 对象并赋值给成员变量 sync。和其他同步工具类一样,CountDownLatch 的实现依赖于 AQS,它是 AQS 共享模式下的一个应用。
7. 线程安全 7.1 线程安全的定义 如果多线程下使用这个类,不过多线程如何使用和调度这个类,这个类总是表示出正确的行为,这个类就是线程安全的。 广泛用于JDK并发容器的实现中。 如果是开发自己的管理工具,需要用更加程序化的方式扫描服务进程、定位死锁,可以考虑使用 Java 提供的标准管理 API,ThreadMXBean,其直接就提供 findDeadlockedThreads ,并不是整个HashMap加锁,而是首先根据hashcode得到该表项应该被存放到哪个段中,然后对该段加锁,并完成put()操作.在多线程环境中,如果多个线程同时进行put()操作,只要被加入的表项不存放在同一个段中 在现代 Java 中,内存排序模型(JMM)已经非常完善,通过 volatile 的 write 或者 read,能保证所谓的 happen-before,也就是避免常被提到的指令重排。
如何创建一个线程 按 Java 语言规范中的说法,创建线程只有一种方式,就是创建一个 Thread 对象。 而从 HotSpot 虚拟机的角度看,创建一个虚拟机线程 有两种方式,一种是创建 Thread 对象,另一种是创建 一个本地线程,加入到虚拟机线程中。 如果从 Java 语法的角度。有两种方法。 Executors JDK 的 java.util.concurrent.Executors 类提供了几个静态的方法,用于创建不同类型的线程池。 原理 JDK 中的线程池通过 HashSet 存储工作者线程,通过 BlockingQueue 来存储待处理任务。 另外,如果待处理队列中没有任务要处理,并且工作者线程数目超过了核心工作者数目,那么,需要减少工作者线程数目。
CountDownLatch 是多线程控制JUt(java.util.concurrent.CountDownLatch)的一个工具类,它被称为 门阀 、 计数器 或者 闭锁 。 反之,如果修改state失败,则会将当前线程加入到AQS的队列中,并阻塞线程。 System.out.println("主线程") 具体请看《线程同步机制:彻底搞懂相关方法wait、join、sleep、notify》 package com.javademo.demo.jucdemo; import java.util.concurrent.CountDownLatch CountDownLatch保证线程一、线程二执行完之后,再执行System.out.println("主线程结束....") package com.javademo.demo.jucdemo; import java.util.concurrent.CountDownLatch 阿里巴巴的数据库连接池Druid中也用了countDownLatch来保证初始化。
一、Java中锁分类 1.1 偏向锁/轻量级锁/重量级锁 这三种锁指的是synchronized锁的状态,Java1.6之前是基于重量级锁,Java1.6之后对synchronized进行了优化,为了减少获取和释放锁带来的性能消耗 在并发环境中,每个线程在获取锁时会先查看此锁维护的等待队列,如果为空,或者当前线程是等待队列的第一个,就占有锁,否则就会加入到等待队列中,以后会按照FIFO(先进先出)的规则从队列中取到自己。 3、例子 在Java的并发包中,ReentrantLock的创建可以指定构造函数的boolean类型来得到公平锁或非公平锁,默认是非公平锁。 二、synchronized锁 详细见Java并发——synchronized锁 三、Lock锁 Java并发——Lock锁 四、synchronized 和 Lock 对比 相同点: 1、synchronized 6、性能不同 在低并发情况下,Synchronized的性能通常优于ReentrantLock;在高并发情况下,ReentrantLock可能表现更好 7、锁的获取状态查询 ReentrantLock可以通过
Java并发设计的7条原则在Java并发编程的世界中,高效且安全地管理线程交互是一项至关重要的挑战本文基于Effective Java 并发章节总结的7条原则这些原则旨在帮助开发者规避常见的并发陷阱,确保程序在多线程环境下的正确性和性能表现同步访问共享可变数据在并发中多线程同时访问共享可变的数据是线程不安全的 ,因为我们无法预估线程的执行顺序,如果不使用一些手段那么可能导致数据不一致的问题在这段代码中,启动一个线程:只要stopRequested不为true就循环自增,而主线程睡眠1秒后将stopRequested backgroundThread.start(); TimeUnit.SECONDS.sleep(1); stopRequested = true; }但是这段代码会导致无限循环,因为Java 不可移植的类似Thread.yield礼让线程 或 调整线程优先级都属于依赖线程调度器,因为无法预估线程的执行顺序即使在当前操作系统和虚拟机上能完成,在其他环境下也有可能失败,这是无法预估的,因为它们依赖于OS中的线程调度器总结对于共享可变数据 不要白嫖,一键三连求求拉~)本篇文章被收入专栏 后端的网络基石,感兴趣的同学可以持续关注喔本篇文章笔记以及案例被收入 Gitee-CaiCaiJava、 Github-CaiCaiJava,除此之外还有更多Java
ThreadLocal的定义 JDK对ThreadLocal的定义如下: TheadLocal提供了线程内部的局部变量:每个线程都有自己的独立的副本;ThreadLocal实例通常是类中的private 例如:在事务中,connection绑定到当前线程来保证这个线程中的数据库操作用的是同一个connection。 ); } },"线程2").start(); } } 运行结果: 在这里插入图片描述 从运行结果,我们可以看出线程1和线程2在ThreadLocal中设置的值相互独立 如果e为null,返回null 如果e不为空且key不相同,则查找下一个位置,继续查找比较,直到e为null退出 在查找的过程中如果发现e不为空,且e的k为空的话,删除当前槽和下一个null槽之间的所有过期
作者个人研发的在高并发场景下,提供的简单、稳定、可扩展的延迟消息队列框架,具有精准的定时任务和延迟队列处理功能。 有点像Hadoop中的MapReduce。 ForkJoin是由JDK1.7之后提供的多线程并发处理框架。ForkJoin框架的基本思想是分而治之。什么是分而治之? Fork/Join框架介绍 位于J.U.C(java.util.concurrent)中,是Java7中提供的用于执行并行任务的框架,其可以将大任务分割成若干个小任务,最终汇总每个小任务的结果后得到最终结果 ; import java.util.concurrent.Future; import java.util.concurrent.RecursiveTask; @Slf4j public class 最后,附上并发编程需要掌握的核心技能知识图,祝大家在学习并发编程时,少走弯路。 ?
线程池 平时有接触过多线程开发的小伙伴们应该都或多或少都有了解、使用过线程池,而《阿里巴巴 Java 手册》里也有一条规范: ? 我们可以把并发执行的任务传递给一个线程池,来替代为每个并发执行的任务都启动一个新的线程。只要池里有空闲的线程,任务就会分配给一个线程执行。 线程池可有效控制最大并发线程数,提高系统资源利用率,同时可以避免过多资源竞争,避免阻塞 线程池可提供定时执行、定期执行、单线程以及并发数控制等功能 直接new Thread的弊端: 每次new Thread 但《阿里巴巴 Java 手册》里有一条规范指明不允许使用Executors创建线程池,具体如下: ? 接下来用一个例子演示一下如何通过ThreadPoolExecutor来创建线程池,这里使用7个参数的构造函数,示例代码如下: package org.zero.concurrency.demo.example.threadpool
PriorityQueue,这是一个(非并发的)优先队列。如上两个队列的操作不会阻塞,如果队列为空,那么获取元素的操作将返回空值。 在 Java 类库中包含了 BlockingQueue 的多种实现,如下:LinkedBlockingQueue 和 ArrayBlockingQueue 是 FIFO 队列,二者分别与 LinkedList 和 ArrayList 类似,但比同步 List 拥有更好的并发性能。 串行线程封闭在 java.util.concurrent 中实现的各种阻塞队列都包含了足够的内部同步机制,从而安全地将对象从生产者线程发布到消费者线程。 双端队列与工作密取Java 6 增加两种容器类型,Deque 和 BlockingDeque,他们分别对 Queue 和 BlockingQueue 进行了扩展。
异步是在一个线程中通过任务切换的方式让多个任务”同时“进展。异步不涉及线程/进程切换,减少了线程/进程创建、上下文切换的开销,更轻量级。 asyncio的核心是事件循环,不断监听/执行队列中的任务。 事件循环 由于asyncio是在一个线程中通过任务切换的方式执行多任务,所以这些任务需要是非阻塞的。 在上面这个async_hello()的例子中,当执行到await asyncio.sleep(1)时,会启动任务asyncio.sleep(1),并交出执行权,让其他任务执行。 number in range(10) ]) print("results=", results) asyncio.run(main()) 运行结果: 6 8 9 5 0 7 3 4 1 2 results= [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] asyncio.gather() 用于收集多个协程以并发执行它们。
[Java] Java 并发包中并发原理剖析之ConcurrentLinkedQueue ConcurrentLinkedQueue是线程安全的无界非阻塞队列,其底层数据结构使用单向链表实现,对于入队和出队操作使用 队列中包含的元素是从head访问的非空节点。通过CAS将节点的引用指向null,自动的会将它从队列中移除。 队列的头部 是队列中时间最长的元素。队列的尾部 是队列中时间最短的元素。新的元素插入到队列的尾部,队列获取操作从队列头部获得元素。 内存一致性效果:当存在其他并发 collection 时,将对象放入 ConcurrentLinkedQueue 之前的线程中的操作 happen-before 随后通过另一线程从 ConcurrentLinkedQueue REFERENCES Java并发编程之美 JDK-API-DOCS
转载请以链接形式标明出处: 本文出自:103style的博客 Java并发编程的艺术笔记 并发编程的挑战 Java并发机制的底层实现原理 Java内存模型 Java并发编程基础 Java中的锁的使用和实现介绍 Java并发容器和框架 Java中的12个原子操作类介绍 Java中的并发工具类 Java中的线程池 Executor框架 ---- 简介 在JDK的并发包里提供了几个非常有用的并发工具类。 } catch (Exception e) { e.printStackTrace(); } System.out.println(" 7 5 -- 1558969130471 2 -- 1558969130471 3 -- 1558969131471 4 -- 1558969131471 6 -- 1558969131471 7 假如有一个需求,要读取几万个文件的数据,因为都是IO密集型任务,我们可以启动几十个线程并发地读取,但是如果读到内存后,还需要存储到数据库中,而数据库的连接数只有10个,这时我们必须控制只有10个线程同时获取数据库连接保存数据
Java 中的并发(Concurrency) 指多个任务在同一时间段内交替执行(宏观上同时进行,微观上可能是 CPU 快速切换调度),目的是提高程序效率,充分利用系统资源(如 CPU、内存、I/O 等) undefined例如:4 核 CPU 同时运行 4 个线程是并行,1 核 CPU 快速切换 4 个线程是并发。三、Java 实现并发的方式Java 提供了多种并发编程工具,核心是通过线程实现:1. // Callable 示例import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import Java 提供 Executors 工具类快速创建线程池:import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors 理解并发是 Java 进阶的关键,尤其在高并发场景(如分布式系统、高流量服务器)中,合理设计并发模型能显著提升系统性能。
java并发中ExecutorService的使用 ExecutorService是java中的一个异步执行的框架,通过使用ExecutorService可以方便的创建多线程执行环境。 第一种方式是使用Executors中的工厂类方法,例如: ExecutorService executor = Executors.newFixedThreadPool(10); 除了newFixedThreadPool Future<String>> futures = executorService.invokeAll(callableTasks); 关闭ExecutorService 如果ExecutorService中的任务运行完毕之后 ExecutorService和 Fork/Join java 7 引入了Fork/Join框架。那么两者的区别是什么呢? 本文的代码请参考https://github.com/ddean2009/learn-java-concurrency/tree/master/ExecutorService
java并发中CountDownLatch的使用 在java并发中,控制共享变量的访问非常重要,有时候我们也想控制并发线程的执行顺序,比如:等待所有线程都执行完毕之后再执行另外的线程,或者等所有线程都准备好了才开始所有线程的执行等 最后在主线程中调用await()方法来等待子线程结束执行。 我们是主线程等待子线程,那么在这个例子中,我们将会看看怎么子线程一起等待到准备好的状态,再一起执行。 思路也很简单,在子线程开始之后,将等待的子线程计数器减一,在主线程中await该计数器,等计数器归零之后,主线程再通知子线程运行。 sync.tryAcquireSharedNanos(1, unit.toNanos(timeout)); } 本文的例子可以参考https://github.com/ddean2009/learn-java-concurrency
9.2 改进的读写锁:StampedLock StampedLock是JDK 8中引入的新的锁机制,可以认为是读写锁的一个改进版本,读写锁虽然分离了读和写,使得读与读之间可以完全并发,但是读和写之间仍然是冲突的 简单粗暴的分散了高并发下的竞争压力。 答案就在LongAdder的java doc中,从我们翻译的那段可以看出,LongAdder适合的场景是统计求和计数的场景,而且LongAdder基本只提供了add方法,而AtomicLong还具有cas 从java doc中可以看出,其适用于统计计数的场景,例如计算qps这种场景。在高并发场景下,qps这个值会被多个线程频繁更新的,所以LongAdder很适合。 ---- 参考: https://www.jianshu.com/p/22d38d5c8c2a 《实战Java高并发程序设计》
Java 并发 线程状态转换 新建(New) 创建后尚未启动。 可运行(Runnable) 可能正在运行,也可能正在等待 CPU 时间片。 時雨:在 《Java 并发核心知识体系精讲》中,参考 Oracle 官方文档,标注实现多线程方式只有两种:实现 Runnable 接口和继承 Thread 类。 $Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745) 如果只想中断 Executor 中的一个线程 它是 JUC 并发包中的核心基础组件。 CountDownLatch 用来控制一个或者多个线程等待多个线程。 在 Java 内存模型中,允许编译器和处理器对指令进行重排序,重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性。
java高并发系列第7篇文章 public class Demo09 { public static boolean flag = true; public static class 要解释这个,我们需要先了解一下java内存模型(JMM),Java线程之间的通信由Java内存模型(本文简称为JMM)控制,JMM决定一个线程对共享变量的写入何时对另一个线程可见。 java帮我们提供了这样的方法,使用volatile修饰共享变量,就可以达到上面的效果,被volatile修改的变量有以下特点: 线程中读取的时候,每次读取都会去主内存中读取共享变量最新的值,然后将其复制到工作内存 java高并发系列目录: 1.java高并发系列-第1天:必须知道的几个概念 2.java高并发系列-第2天:并发级别 3.java高并发系列-第3天:有关并行的两个重要定律 4.java高并发系列 - 第4天:JMM相关的一些概念 5.java并发系列第5天-深入理解进程和线程 6.java高并发系列 - 第6天:线程的基本操作