基于对多线程的使用和理解,对多线程使用的的类做了一个归类,并对相关内容进行一个简单的分解,如果需要详细了解,请自己查询相关资料。
上图是大家经常在多线程中或者编程中使用的类
变量
一个线程运行时都有一个线程栈,线程栈保存了线程运行时候变量值信息。当线程访问某一个
对象时候值的时候,首先通过对象的引用找到对应在堆内存的变量的值,然后把堆内存
变量的具体值load到线程本地内存中,建立一个变量副本,之后线程就不再和对象在堆内存变量
值有任何关系,而是直接修改副本变量的值。
Atomic
包含多个原子操作类,比较常用的到的AtomicInteger,AtomicLong。
处理器基本都支持CAS,借助硬件的相关指令,CAS的基本思路就是,如果这个地址上的值
和期望 的值相等,则给其赋予新值,否则不做任何事儿,但是要返回原值是多少。
采用UnSafe的compareAndSwap方法
对于Atomic能实现线程同步,其实是CPU和内存,利用CPU的多处理能力,实现硬件层面的
阻塞, 再加上类似volatile变量的特性即可实现基于原子操作的线程安全。
volatile
volatile不是原子操作,只是定义的变量存储在主内存中,
1.每次获取数据都是从主内存中重新读取。
2.修改数据后,需要刷新到主内存中。
使用场景
1.写入的变量值不依赖读取的变量值。
2.该变量不是另外变量表达式中的值。
transient
常用来对该变量不进行序列化,对于存储在硬盘或者其他的数据流传输中,这个字段值为空。
简单来说就是 当对象存储时,它的值不需要维持。
ThreadLocal
ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地
改变自己的副本,而不会影响其它线程所对应的副本。副本的实现是采用
ThreadLocal类中有一个Map,用于存储每一个线程的变量副本,
Map中元素的键为线程对象,而值对应线程的变量副本。
锁的类型
synchronized
Synchronized是Java并发编程中最常用的用于保证线程安全的方式,其使用相对也比较简单。
如果需要对其原理进行分析,需要对监视器锁(monitor)
指令(monitorenter,monitorexit) 机制进行了解。
Lock
ReentrantLock是一个可重入的互斥锁,又被称为“独占锁”,可以被单个线程多次占有,
分为“公平锁”和“非公平锁”。通过一个FIFO的等待队列来管理获取该锁所有线程的。
ReadWriteLock :读写锁,分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥。
Condition
Condition是个接口,基本的方法就是await()和signal()方法;
Condition依赖于Lock接口,生成一个Condition的基本代码是lock.newCondition()
调用Condition的await()和signal()方法,都必须在lock保护之内,就是说必须在
lock.lock()和 lock.unlock之间才可以使用
Conditon中的await()对应Object的wait();
Condition中的signal()对应Object的notify();
Condition中的signalAll()对应Object的notifyAll()。
concurrent
这个架包下有很多工具类,先从BlockingQueue阻塞队列开始,队列一般采用的是先进先出
当队列中填满数据的情况下,生产者端的所有线程都会被自动阻塞(挂起),直到队列中有空的位置,线程被自动唤醒。
1. ArrayBlockingQueue
基于数组的阻塞队列实现,在ArrayBlockingQueue内部,维护了一个定长数组,以便缓存队列中的数据对象,这是一个常用的阻塞队列,除了一个定长数组外,ArrayBlockingQueue内部还保存着两个整形变量,分别标识着队列的头部和尾部在数组中的位置。
ArrayBlockingQueue在生产者放入数据和消费者获取数据,都是共用同一个锁对象,由此也意味着两者无法真正并行运行。
2. LinkedBlockingQueue
基于链表的阻塞队列,同ArrayListBlockingQueue类似,其内部也维持着一个数据缓冲队列(该队列由一个链表构成),当生产者往队列中放入一个数据时,队列会从生产者手中获取数据,并缓存在队列内部,而生产者立即返回;只有当队列缓冲区达到最大值缓存容量时(LinkedBlockingQueue可以通过构造函数指定该值),才会阻塞生产者队列。LinkedBlockingQueue之所以能够高效的处理并发数据,还因为其对于生产者端和消费者端分别采用了独立的锁来控制数据同步,这也意味着在高并发的情况下生产者和消费者可以并行地操作队列中的数据,以此来提高整个队列的并发性能。
作为开发者,我们需要注意的是,如果构造一个LinkedBlockingQueue对象,而没有指定其容量大小,LinkedBlockingQueue会默认一个类似无限大小的容量(Integer.MAX_VALUE),这样的话,如果生产者的速度一旦大于消费者的速度,也许还没有等到队列满阻塞产生,系统内存就有可能已被消耗殆尽了。
3. DelayQueue
DelayQueue中的元素只有当其指定的延迟时间到了,才能够从队列中获取到该元素。DelayQueue是一个没有大小限制的队列,因此往队列中插入数据的操作(生产者)永远不会被阻塞,而只有获取数据的操作(消费者)才会被阻塞。
使用场景:
DelayQueue使用场景较少,但都相当巧妙。
4. PriorityBlockingQueue
基于优先级的阻塞队列(优先级的判断通过构造函数传入的Compator对象来决定),但需要注意的是PriorityBlockingQueue并不会阻塞数据生产者,而只会在没有可消费的数据时,阻塞数据的消费者。因此使用的时候要特别注意,生产者生产数据的速度绝对不能快于消费者消费数据的速度,否则时间一长,会最终耗尽所有的可用堆内存空间。在实现PriorityBlockingQueue时,内部控制线程同步的锁采用的是公平锁。
需要注意的是,如果按poll()/take()方法获取出来的数据是排序的,因为每次获取的数据吧保证优先级最高的放在前面,其他的元素不排序。每次消费一个,马上排序一个优先级最高的到头部。
5. SynchronousQueue
是一个没有数据缓冲的BlockingQueue,生产者线程对其的插入操作put必须等待消费者的
移除操作take,反过来也一样。
线程池
在多线程中,线程池是非常常用的工具。Java里面线程池的顶级接口是Executor,但是严格
意义上讲Executor并不是一个线程池,而只是一个执行线程的工具。真正的线程池接口
是ExecutorService。
要配置一个线程池是比较复杂的,尤其是对于线程池的原理不是很清楚的情况下,
很有可能配置的线程池不是较优的,因此在Executors类里面提供了一些静态工厂,
生成一些常用的线程池。
1. newSingleThreadExecutor
创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。
2.newFixedThreadPool
创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程,在内部是有一个queue存储提交的线程,这个是无固定大小的。
3. newCachedThreadPool
ExecutorService pool = Executors.newCachedThreadPool();
创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,
那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。
4.newScheduledThreadPool
ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor(1);
创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求,
输入参数为线程池保持的活跃线程数量,但是最大的线程数量为无限大小。
ThreadPoolExecutor是Executors类的底层实现。
在JDK帮助文档中,有如此一段话:
“强烈建议程序员使用较为方便的Executors工厂方法Executors.newCachedThreadPool()(无界线程池,可以进行自动线程回收)、Executors.newFixedThreadPool(int)(固定大小线程池)Executors.newSingleThreadExecutor()(单个后台线程)。
相关推荐
在IT行业中,多线程并行执行是一种常见的优化策略,特别是在处理大数据量或者需要高性能计算的任务时。"CountDownLatch" 和 "Thread" 是Java编程语言中实现多线程并行执行的关键工具,它们有助于提高程序的运行效率...
详解Java多线程处理List数据 Java多线程处理List数据是指在Java编程中,使用多线程技术来处理List数据的操作。这种操作可以提高程序的执行效率和性能,特别是在处理大规模数据时。下面将详细介绍Java多线程处理List...
本文将深入探讨Java多线程的核心概念、创建方式以及相关API的使用。 首先,我们要理解线程的基本概念。在操作系统层面,进程是资源分配的基本单位,而线程则是执行的基本单位。一个进程可以包含多个线程,它们共享...
Java多线程整理汇总思维导图
java多线程排序源程序,三种排序算法。希尔排序,快速排序,堆排序。
总之,Java多线程技术结合分页读取策略能有效提升数据库操作的效率,但同时也需要关注并发控制、资源管理以及异常处理等多个方面的细节,确保程序的稳定性和效率。在实际开发中,应根据项目需求和资源限制,选择合适...
资源名称:Java多线程并发相关资料汇总 资源目录: 【】JavaConcurrencyinPractice 【】JavaThreads(3rdEdition) 【】JAVA多线程并发 【】Java多线程并发访问解决方案 【】java多...
多线程并行执行,然后汇总结果、多线程并行执行,汇总结果。 MultiThread,ResultVo> multiThread = new MultiThread,ResultVo>(threadList){ @Override public List<ResultVo> outExecute(int currentThread...
下面将详细讲解Java多线程下载的相关知识点: 1. **线程基础**:在Java中,线程是程序中的执行流。`Thread`类是所有线程的基类,我们可以通过继承它或实现`Runnable`接口来创建线程。创建线程主要有两种方式:直接...
多线程是计算机编程中的一个核心概念,尤其是在Java、C++等高级编程语言中,它被广泛用于提高程序的执行效率。本汇总资料主要聚焦于多线程的学习,旨在帮助开发者深入理解并熟练掌握这一技术。 多线程是指在单个...
内容概要:本文汇总了有关Java多线程方面的28个面试题目及其详细解答,涵盖了线程的基础概念、线程创建方法、线程控制(启动、同步、休眠、停止)、高级特性和应用技巧(线程局部存储、线程池、同步器等)。...
本文将通过Java编程语言的示例代码,探讨如何实现多线程相加的场景,并分析多线程在大数据处理中的优势及潜在问题。 首先,我们构建一个基础的多线程环境。这里定义了一个`MyThread`类,这个类包含两个静态变量:`...
在Java编程中,多线程下载文件是一种优化大文件下载效率的技术。它通过将一个大文件分割成多个小部分,然后在不同的线程中并行下载这些部分,从而充分利用网络带宽,加快下载速度。本源码实现了这样一个功能,让下载...
在Java编程语言中,多线程是实现并发执行任务的关键特性。`Runnable`接口是Java提供的一个核心机制,用于创建并运行线程。本实例将深入讲解如何使用`Runnable`接口来实现多线程,并通过具体的`TestRunnable.java`源...
在编程领域,多线程是一种常见且重要的技术,特别是在Java这样的多线程支持良好的语言中。本主题聚焦于“西南科技大学”的一个Java综合实验,该实验旨在通过多线程实现阶乘运算。在这个实验中,学生将学习如何利用...
1. **Java多线程基础**:在Java中,多线程是并发处理的核心,允许程序同时执行多个任务。通过创建Thread对象或实现Runnable接口,开发者可以创建新的执行线程。在下载工具中,每个线程负责下载文件的一个部分。 2. ...
以下是关于Java多线程实现的详细介绍。多线程是指一个程序中可以同时运行多个线程(Thread),每个线程可以看作是程序执行的独立路径。在多线程环境中,CPU时间可以被多个线程共享,从而实现并发执行。 Java中的多...
本篇内容涵盖了 Java 集合框架中 `Set`、`List` 和 `Map` 的核心概念及其实现细节,同时还包括了数组的基本用法以及多线程和 XML 解析的基础知识。这些内容对于 Java 开发者来说是非常重要的基础知识,掌握它们可以...
java多线程编程总结,很详细的文档。
### Java多线程的核心概念与应用 #### 一、多线程的基本介绍 在现代软件开发中,特别是在Java这样的高级编程语言中,多线程技术是实现并发处理的关键手段之一。通过多线程,程序可以在同一时间执行多个任务,极大...