JAVA多线程-内存模型、三大特性、线程池
一、线程的三大特性
原子性、可见性、有序性
1)原子性,即一个操作或者多个操作要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。原子性其实就是保证数据一致、线程安全一部分。
2)可见性,即当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。
3)有序性,即程序执行的顺序按照代码的先后顺序执行。
二、JAVA多线程的内存模型
共享内存模型指的就是Java内存模型(简称JMM),JMM决定一个线程对共享变量的写入时,能对另一个线程可见。从抽象的角度来看,JMM定义了线程和主内存之间的抽象关系:线程之间的共享变量存储在主内存(main memory)中,每个线程都有一个私有的本地内存(local memory),本地内存中存储了该线程以读/写共享变量的副本。本地内存是JMM的一个抽象概念,并不真实存在。它涵盖了缓存,写缓冲区,寄存器以及其他的硬件和编译器优化。
从上图来看,线程A与线程B之间如要通信的话,必须要经历下面2个步骤:
1. 首先,线程A把本地内存A中更新过的共享变量刷新到主内存中去。
2. 然后,线程B到主内存中去读取线程A之前已更新过的共享变量。
如上图所示,本地内存A和B有主内存中共享变量x的副本。假设初始时,这三个内存中的x值都为0。线程A在执行时,把更新后的x值(假设值为1)临时存放在自己的本地内存A中。当线程A和线程B需要通信时,线程A首先会把自己本地内存中修改后的x值刷新到主内存中,此时主内存中的x值变为了1。随后,线程B到主内存中去读取线程A更新后的x值,此时线程B的本地内存的x值也变为了1。
从整体来看,这两个步骤实质上是线程A在向线程B发送消息,而且这个通信过程必须要经过主内存。JMM通过控制主内存与每个线程的本地内存之间的交互,来为java程序员提供内存可见性保证。
总结:什么是Java内存模型:java内存模型简称jmm,定义了一个线程对另一个线程可见。共享变量存放在主内存中,每个线程都有自己的本地内存,当多个线程同时访问一个数据的时候,可能本地内存没有及时刷新到主内存,所以就会发生线程安全问题。
三、Volatile
Volatile 关键字的作用是变量在多个线程之间可见。
1)由于线程之间是不可见的,读取的是副本,所以会没有及时读取到主内存结果。解决办法使用Volatile关键字将解决线程之间可见性, 强制线程每次读取该值的时候都去“主内存”中取值
2)Volatile非原子性
由于Volatile不具有原子性,需要Automic原子类。
AtomicInteger atomicInteger = new AtomicInteger(0);
3)volatile与synchronized区别
仅靠volatile不能保证线程的安全性。(原子性)
a、volatile轻量级,只能修饰变量。synchronized重量级,还可修饰方法
b、volatile只能保证数据的可见性,不能用来同步,因为多个线程并发访问volatile修饰的变量不会阻塞。
c、synchronized不仅保证可见性,而且还保证原子性,因为,只有获得了锁的线程才能进入临界区,从而保证临界区中的所有语句都全部执行。多个线程争抢synchronized锁对象时,会出现阻塞。
d、线程安全性
线程安全性包括两个方面,①可见性。②原子性。
从上面自增的例子中可以看出:仅仅使用volatile并不能保证线程安全性。而synchronized则可实现线程的安全性。
四、ThreadLoca
1)ThreadLocal提高一个线程的局部变量,访问某个线程拥有自己局部变量。当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
2)ThreadLocal的接口方法
ThreadLocal类接口很简单,只有4个方法,我们先来了解一下:
a、void set(Object value)设置当前线程的线程局部变量的值。
b、public Object get()该方法返回当前线程所对应的线程局部变量。
c、public void remove()将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。
d、protected Object initialValue()返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法,在线程第1次调用get()或set(Object)时才执行,并且仅执行1次。ThreadLocal中的缺省实现直接返回一个null。
public static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() {
protected Integer initialValue() {
return 0;
};
};
3)ThreadLoca实现原理
ThreadLoca通过map集合
Map.put(“当前线程”,值);
五、线程池
1)什么是线程池
线程池是指在初始化一个多线程应用程序过程中创建一个线程集合,然后在需要执行新的任务时重用这些线程而不是新建一个线程。线程池中线程的数量通常完全取决于可用内存数量和应用程序的需求。然而,增加可用线程数量是可能的。线程池中的每个线程都有被分配一个任务,一旦任务已经完成了,线程回到池子中并等待下一次分配任务。
2)线程池的作用
基于以下几个原因在多线程应用程序中使用线程是必须的:
1. 线程池改进了一个应用程序的响应时间。由于线程池中的线程已经准备好且等待被分配任务,应用程序可以直接拿来使用而不用新建一个线程。
2. 线程池节省了CLR 为每个短生存周期任务创建一个完整的线程的开销并可以在任务完成后回收资源。
3. 线程池根据当前在系统中运行的进程来优化线程时间片。
4. 线程池允许我们开启多个任务而不用为每个线程设置属性。
5. 线程池允许我们为正在执行的任务的程序参数传递一个包含状态信息的对象引用。
6. 线程池可以用来解决处理一个特定请求最大线程数量限制问题。
3)线程池的4中创建方式
Java通过Executors(jdk1.5并发包)提供四种线程池,分别为:
1.newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。(常用)
2.newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
3.newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
4.newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO,
LIFO, 优先级)执行。
JAVA多线程-内存模型、三大特性、线程池的更多相关文章
- Java多线程学习(八)线程池与Executor 框架
目录 历史优质文章推荐: 目录: 一 使用线程池的好处 二 Executor 框架 2.1 简介 2.2 Executor 框架结构(主要由三大部分组成) 2.3 Executor 框架的使用示意图 ...
- 线程池 | Java多线程,彻底搞懂线程池
熟悉Java多线程编程的同学都知道,当我们线程创建过多时,容易引发内存溢出,因此我们就有必要使用线程池的技术了. 最近看了一些相关文章,并亲自研究了一下源码,发现有些文章还是有些问题的,所以我也总结了 ...
- java多线程系类:JUC线程池:03之线程池原理(二)(转)
概要 在前面一章"Java多线程系列--"JUC线程池"02之 线程池原理(一)"中介绍了线程池的数据结构,本章会通过分析线程池的源码,对线程池进行说明.内容包 ...
- java多线程系类:JUC线程池:04之线程池原理(三)(转)
转载请注明出处:http://www.cnblogs.com/skywang12345/p/3509960.html 本章介绍线程池的生命周期.在"Java多线程系列--"基础篇& ...
- java多线程系类:JUC线程池:02之线程池原理(一)
在上一章"Java多线程系列--"JUC线程池"01之 线程池架构"中,我们了解了线程池的架构.线程池的实现类是ThreadPoolExecutor类.本章,我 ...
- java多线程系类:JUC线程池:01之线程池架构
概要 前面分别介绍了"Java多线程基础"."JUC原子类"和"JUC锁".本章介绍JUC的最后一部分的内容--线程池.内容包括:线程池架构 ...
- Java多线程内存模型
Java虚拟机规范中试图定义一种Java内存模型(Java Memory Model,JMM)来屏蔽掉各种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到一致的并发效果.在此之前 ...
- (CSDN 迁移) JAVA多线程实现-可回收缓存线程池(newCachedThreadPool)
在前两篇博客中介绍了单线程化线程池(newSingleThreadExecutor).可控最大并发数线程池(newFixedThreadPool).下面介绍的是第三种newCachedThreadPo ...
- java多线程系类:JUC线程池:06之Callable和Future(转)
概要 本章介绍线程池中的Callable和Future.Callable 和 Future 简介示例和源码分析(基于JDK1.7.0_40) 转载请注明出处:http://www.cnblogs.co ...
随机推荐
- Java学习笔记之——Set容器
Set容器: 特点:无序.不重复 Set实现了Collection接口 常用方法见API 遍历: 迭代器.foreach 常用类: HashSet: 底层结构:HashMap,使用其中的键来存储元素 ...
- .NET平台下使用Redis
using DBI.SaaS.Web.Models.Args; using Rafy; using StackExchange.Redis; using System; using System.Co ...
- react create-react-app 跨域
"proxy":"http://youAddr.com" 直接到根目录package.json里增加上面这行就行了,改成自己需要的地址.
- SuperMap -WebGL 实现地球的背景透明并显示自定义图片
实现效果如图: 实现代码如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset ...
- 功能强大的PDF实用工具
PDF实用工具(PDFTool)是北京博信施科技有限有限公司研制开发的一款专门提供对PDF文件进行编辑.加工的处理软件.本软件具有对PDF文件进行分割.结合.加密.解密.添加水印.设定有效期限等多种功 ...
- 关于JPasswordField的getText()方法过时问题解决
这几天想做一个登陆界面,用Jframe做,连接数据库时发现JPasswordField的getText()过时了,没法使用.查了资料发现改成了: try{ String sql="SELEC ...
- Linux 中磁盘容量配额
linux的设计之处就是为了多用户同时执行不同的任务,但是硬件资源是有限的,不能让一个用户无限制的上传文件,如果不加以限制,那么磁盘最终将会被充满,对此我们应该使用uquota来加以限制. 1.quo ...
- ORA-02030: can only select from fixed tables/views
有时候给一些普通用户授予查询系统对象(例如dynamic performance views)权限时会遇到"ORA-02030: can only select from fixed tab ...
- Oracle 12c RAC 安装文档
参考文档: https://docs.oracle.com/en/database/oracle/oracle-database/12.2/cwlin/index.html https://docs. ...
- Mysql 获取表设计查询语句
SELECT COLUMN_NAME 列名, COLUMN_TYPE 数据类型, DATA_TYPE 字段类型, CHARACTER_MAXIMUM_LENGTH 长度, IS_NULLABLE 是否 ...