Java并发编程实战笔记—— 并发编程2
1、ThreadLocal
Java中的ThreadLocal类可以让你创建的变量只被同一个线程进行读和写操作。因此,尽管有两个线程同时执行一段相同的代码,而且这段代码又有一个指向同一个ThreadLocal变量的引用,但是这两个线程依然不能看到彼此的ThreadLocal变量域。ThreadLocal类提供了get和set等访问接口,这些方法为每个线程都存有一个独立的副本,因此每次get总是返回当前线程上一次最小使用set设置的值。
private ThreadLocal myThreadLocal = new ThreadLocal();
这样实例化一个ThreadLocal类,每个线程仅需要实例化一次即可。
myThreadLocal.set("A local value");
String threadLocalValue = (String) myThreadLocal.get();
这样使用set和get来存储和读取一个String对象,因为get返回的是一个Object对象,所以需要强制类型转换,set()方法则依赖一个Object对象参数。
为了不使用强制类型转换可以使用泛型来实例化一个ThreadLocal对象。
private ThreadLocal myThreadLocal1 = new ThreadLocal<String>();
这样读取的时候就不需要进行强制类型转换了
myThreadLocal1.set("Hello ThreadLocal");
String threadLocalValues = myThreadLocal.get();
然后我们还可以可以通过ThreadLocal子类的实现,并覆写initialValue()方法,就可以为ThreadLocal对象指定一个初始化值。
private ThreadLocal myThreadLocal = new ThreadLocal<String>() {
@Override protected String initialValue() {
return "This is the initial value";
}
};
这样指定的初始值对所有线程都是可见的,在set方法被调用之前所有线程读取到的都将是这个初始值。
一个完整的ThreadLocal示例
class myThread implements Runnable{
private ThreadLocal myThreadLocal = new ThreadLocal<String>(){
@Override
protected String initialValue() {
return "a Initialization value ";
}
}; @Override
public void run() {
System.out.println(myThreadLocal.get());
myThreadLocal.set("" + Math.random());
System.out.println(myThreadLocal.get());
}
} public class Fun { public static void main(String[] args) {
myThread myRunnabe = new myThread();
Thread myThread1 = new Thread(myRunnabe);
Thread myThread2 = new Thread(myRunnabe); myThread1.start();
myThread2.start(); }
}
输出:
a Initialization value
a Initialization value
0.3672775208272421
0.5694837916871707
2、不变性
如果某个对象在创建之后就不能被修改,那么这个对象就被称为不可变对象。因为其状态将不会被改变,所以不同线程访问该对象的时候是安全的
满足以下条件的对象是不可变的:
- 对象在创建以后其状态就不能被修改
- 对象的所有域都是final类型的
- 对象是正确创建的
在可变对象基础上构建不可变对象
public final class Aclass{
private final Set<String> set = new HashSet<String>();
public Aclass(){
set.add("aaa");
set.add("bbb");
set.add("ccc");
}
public boolean isSet(String word){
return set.contains(word);
}
}
这样一个类是可变,它的set对象是可变的,但是这个对象在创建之后就是不可改变的了,对于final类型的set对象只能访问不能被修改。
3、安全发布
在某些情况下我们希望在多个线程之间共享对象,此时必须保证安全的进行共享。
public Holder holder;
public void init(){
holder = new Holder(42);
}
这个holder看起来是一个不可变对象,但其实它并不是,他并不满足“对象是正确创建的”这个条件,某些线程将会看到尚未创建完场的对象
可变对象必须通过安全的方式来进行发布,这通常都意味着在发布和使用该对象的线程都必须使用同步。
要安全得发布一个对象,对象的引用以及对象的状态必须同时对其他线程可见,一个正确构造的对象可以通过以下方式来正确发布:
- 在静态初始化函数中初始化一个对象引用
public static Holder holder = new Holder(42);
- 将对象的引用保存到volatile类型的域或者AtomicReferance对象中
- 将对象的引用保存到某个正确构造对象的final类型中
- 将对象得引用保存到一个由锁保护的域中
在线程安全库中的容器提供以下的安全发布保证:
- 通过将一个键或者值放入Hashtable、synchronizedMap或者ConcurrentMap中,可以安全地将它发布给任何从这些容器中访问它的线程(无论是直接访问还是通过迭代器访问)
- 通过将某个元素放入Vector、CopyOnWriteArrayList、CopyOnWriteArraySet、synchronizedList或synchronizedSet中,可以将该元素安全地发布到任何从这些容器中访问该元素的线程
- 通过将某个元素放入BlockingQueue或者ConcurrentLinkedQueue中,可以将该元素安全地发布到任何从这些队列中访问该元素的线程。
事实不可变对象:如果对象从技术上来看是可变的,但其状态在发布以后就不会在改变,那么把这种对象称为“事实不可变对象”,刚刚的holder就是一个事实不可变对象。
所以最后对象的发布需求取决于它的可变性:
- 不可变对象可以通过任意机制发布
- 事实不可变对象必须通过安全方向进行发布
- 可变对象必须通过安全方式进行发布,并且必须是线程安全的或者由某个锁保护起来的
在并发程序中使用和共享对象时,可以使用以下一些实用的策略:
- 线程关闭:对象只能由一个线程拥有,对象被封闭在该线程中,并且只能由这个线程修改
- 只读共享:任何线程都不能修改的对象。
- 线程安全共享:在线程内部实现同步。
- 保护对象:通过持有特定的锁才能访问
Java并发编程实战笔记—— 并发编程2的更多相关文章
- Java并发编程实战笔记—— 并发编程1
1.如何创建并运行java线程 创建一个线程可以继承java的Thread类,或者实现Runnabe接口. public class thread { static class MyThread1 e ...
- Java并发编程实战笔记—— 并发编程4
1.同步容器类 同步容器类都是线程安全的,但在某些情况下可能需要额外的客户端加锁保护复合操作. 容器上常见的复合操作包括但不限于:迭代(反复访问数据,直到遍历完容器中所有的元素为止).跳转(根据指定顺 ...
- Java并发编程实战笔记—— 并发编程3
1.实例封闭 class personset{ private final Set<Person> myset = new HashSet<Person>(); public ...
- Java并发编程实战.笔记十一(非阻塞同步机制)
关于非阻塞算法CAS. 比较并交换CAS:CAS包含了3个操作数---需要读写的内存位置V,进行比较的值A和拟写入的新值B.当且仅当V的值等于A时,CAS才会通过原子的方式用新值B来更新V的值,否则不 ...
- Java并发编程实战 01并发编程的Bug源头
摘要 编写正确的并发程序对我来说是一件极其困难的事情,由于知识不足,只知道synchronized这个修饰符进行同步. 本文为学习极客时间:Java并发编程实战 01的总结,文章取图也是来自于该文章 ...
- 【ARM-Linux开发】OpenACC并行编程实战笔记
今年运气比较好,学了cuda之后,了解到了gpu的另两种使用语言opencl和openacc, opencl(Open Computing Language ,开放计算语言)是面向异构系统的并行编程 ...
- 多线程-java并发编程实战笔记
线程安全性 编写线程安全的代码实质上就是管理对状态的访问,而且通常都是共享的,可变的状态. 一个对象的状态就是他的数据,存储在状态变量中,比如实例域或静态域.所谓共享是指一个对象可以被多个线程访问:所 ...
- java并发编程实战笔记---(第四章)对象的组合
4.1设计线程安全的类 包含三个基本要素: 1.找出构成对象状态的所有变量 2.找出约束状态变量的不变性条件 2.简历对象状态的并发访问管理策略 对象的状态: 域 基本类型所有域, 引用类型包括被引用 ...
- java并发编程实战笔记---(第三章)对象的共享
3.1 可见性 synchronized 不仅实现了原子性操作或者确定了临界区,而且确保内存可见性. *****必须在同步中才能保证:当一个线程修改了对象状态之后,另一个线程可以看到发生的状态变化. ...
随机推荐
- Oracle数据库---包
--根据员工号或员工姓名获取员工的信息--根据员工号或员工姓名删除员工的信息--创建包规范CREATE OR REPLACE PACKAGE overload_pkgIS FUNCTION get_i ...
- VMware下的Centos7实践Kvm虚拟化(通俗易懂)
虽然网上已经有很多关于kvm安装的教程了,但我还是看得头晕,有的教程里安装的包很多,有的很少,也没说明那些安装包的作用是干嘛的,用的命令也不一样,也没解释命令的意思是什么. 我重新写一个教程,尽量通俗 ...
- 学Redis这篇就够了
Redis 简介 Redis 优势 Redis 数据类型 string hash list set Zset 小总结 基本命令 发布订阅 简介 实例 发布订阅常用命令 事务 实例 Redis 事务命令 ...
- C语言学习书籍推荐《C语言入门经典(第5版)》下载
霍尔顿 (Ivor Horton) (作者), 杨浩 (译者) 下载地址:点我 C语言是每一位程序员都应该掌握的基础语言.C语言是微软.NET编程中使用的C#语言的基础:C语言是iPhone.iPad ...
- 查询亿级数据毫秒级返回!Elasticsearch 是如何做到的?
掌握搜索技能,才能在庞大的数据集中找到准确的目标.本篇就带你进入另一个非凡的旅程,即使你没有像Google或Baidu一样强大的技术,一样也可以做出与之相匹敌的用户体验. 搜索是现代软件必备的一项基础 ...
- ElasticStack学习(九):深入ElasticSearch搜索之词项、全文本、结构化搜索及相关性算分
一.基于词项与全文的搜索 1.词项 Term(词项)是表达语意的最小单位,搜索和利用统计语言模型进行自然语言处理都需要处理Term. Term的使用说明: 1)Term Level Query:Ter ...
- 用框架名唬人谁都会,那你知道Web开发模式吗?——莫问前程莫装逼
前言:这两天总结了一些Servlet和JSP里面的知识,写了几篇博客,果然有种“温故而知新”的感觉,学完这些,继续前行,开始整合框架里的知识,框架虽好,可底层原理该掌握的也得掌握,防止以后做项目的时候 ...
- WGS84坐标与web墨卡托投影坐标转换
许久没有使用坐标转换,记忆有些模糊了,以后还是会用到,先将WGS84与web墨卡托转换复习一下: 1.84转web墨卡托 //核心公式 平面坐标x = 经度*20037508.34/108 平面坐标y ...
- Android生成随机数
此方法通过把当前时刻长整型数传给Random对象,让它产生的值随着时间而变化. String s = ""; Random ran =new Random(System.curre ...
- storm入门demo
一.storm入门demo的介绍 storm的入门helloworld有2种方式,一种是本地的,另一种是远程. 本地实现: 本地写好demo之后,不用搭建storm集群,下载storm的相关jar包即 ...