当访问共享的可变数据时,通常需要使用同步。一种避免使用同步的方式就是不共享数据。

如果仅在单线程内访问数据,就不需要同步。这种技术被称为线程封闭(Thread Confinement),它是实现线程安全最简单的方式之一。当某个对象封闭在一个线程中时,这种用法将自动实现安全性,即使被封闭的对象本身不是线程安全的。

Swing中大量使用线程封闭技术将可视化组件和数据模型封闭到Swing的事件分发线程中实现线程安全性。

另一个常见的例子是JDBC(Java Database Connectivity)的Connection对象。JDBC并没有要求Connection是线程安全的对象。在典型的服务器应用程序中,线程从线程池中获取一个Connection对象,并且用该对象来处理请求,使用完之后再返回给连接池。由于大多数的请求都是由单个线程采用同步的方式来处理,并且在Connection对象返回之前,连接池不会再将它分配给其他线程,相当于隐式地将Connection对象封闭在线程中。

Java并没强制规定某个变量必须由锁保护,也没有强制把某个对象封闭在线程中。线程封闭是在程序设计中的一个考虑因素,必须由程序去实现。

Java语言提供了一些机制来帮助维持线程的封闭性,例如局部变量和ThreadLocal类。

Ad-hoc线程封闭

Ad-hoc线程封闭是指,维护线程封闭性的职责完全由程序来承担。

在volatile变量上存在一种特殊的线程封闭。只要你能确保只有单个线程对共享的volatile变量执行写入操作,那么就可以安全地在这些共享的volatile变量上执行"读取—修改—写入"的操作。这种情况下相当于将修改操作封闭在单个线程中以防止发生竞态条件,并且volatile的可见性还确保其他的线程能看到最新的值。

栈封闭

局部变量的固有属性之一就是封闭在执行的线程中。它们位于执行线程的栈中,其他线程无法访问这个栈。栈封闭不要与核心类库中的ThreadLocal混淆。

栈内的基本数据类型不会被发布出去,但是对象被发布出去了,那么封闭性将被破坏。如果在线程内部使用了非线程安全的对象,那么该对象仍然是线程安全的。

ThreadLocal类

维持线程封闭性一种更规范的方法是使用ThreadLocal,这个类能使线程中的某个值与保存值的对象关联起来。ThreadLocal提供了get与set等访问接口或方法,这些方法为每个使用改变量的线程都存有一份独立的副本,因此get总是返回由当前执行线程在调用set时设置的最新值。

ThreadLocal对象通常用于防止对可变的单实例变量(Singleton)或全局变量进行共享。

在单线程应用程序中可能会维持一个全局的数据库连接,并在程序启动的时候初始化这个连接对象,从而避免在调用每个方法时都要传递一个Connection对象。当多个线程在没有协同的情况下就使用全局变量,就不是线程安全的。通过将JDBC的连接保存到ThreadLocal对象中,每个线程都会拥有属于自己的连接。

如果需要频繁执行的操作需要一个临时的对象,例如一个缓冲区,又希望避免每次执行时重新分配该临时对象,就可以使用这项技术。而不是使用共享的静态缓冲区(这个需要锁机制)。

Java并发编程(七)线程封闭的更多相关文章

  1. Java并发编程:线程封闭和ThreadLocal详解

    转载请标明出处: http://blog.csdn.net/forezp/article/details/77620769 本文出自方志朋的博客 什么是线程封闭 当访问共享变量时,往往需要加锁来保证数 ...

  2. Java并发编程:线程池的使用

    Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了, ...

  3. Java并发编程:线程间协作的两种方式:wait、notify、notifyAll和Condition

    Java并发编程:线程间协作的两种方式:wait.notify.notifyAll和Condition 在前面我们将了很多关于同步的问题,然而在现实中,需要线程之间的协作.比如说最经典的生产者-消费者 ...

  4. Java并发编程:线程池的使用(转)

    Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了, ...

  5. Java并发编程:线程控制

    在上一篇文章中(Java并发编程:线程的基本状态)我们介绍了线程状态的 5 种基本状态以及线程的声明周期.这篇文章将深入讲解Java如何对线程进行状态控制,比如:如何将一个线程从一个状态转到另一个状态 ...

  6. Java 并发编程:线程间的协作(wait/notify/sleep/yield/join)

    Java并发编程系列: Java 并发编程:核心理论 Java并发编程:Synchronized及其实现原理 Java并发编程:Synchronized底层优化(轻量级锁.偏向锁) Java 并发编程 ...

  7. (转)Java并发编程:线程池的使用

    背景:线程池在面试时候经常遇到,反复出现的问题就是理解不深入,不能做到游刃有余.所以这篇博客是要深入总结线程池的使用. ThreadPoolExecutor的继承关系 线程池的原理 1.线程池状态(4 ...

  8. Java并发编程:线程池的使用(转载)

    转载自:https://www.cnblogs.com/dolphin0520/p/3932921.html Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实 ...

  9. Java并发编程:线程池的使用(转载)

    文章出处:http://www.cnblogs.com/dolphin0520/p/3932921.html Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实 ...

  10. [转]Java并发编程:线程池的使用

    Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了, ...

随机推荐

  1. Swift中混编OC第三方库

    现在Swift的第三方库还比较少,有时候需要使用OC的第三方库,其实也是很容易的.   我们使用如下步骤: 1.新建的Swift项目,第一次创建OC文件时会询问是否生成 桥接头,选择是的话会生成一个桥 ...

  2. Kubernetes环境下如何运行Coherence缓存集群

    Oracle官方出了一个如何在Docker环境下运行Coherence的技术文档,大家可以参考: https://github.com/oracle/docker-images/tree/master ...

  3. WebLogic Cluster Sevlet的配置

    虽然生产环境中不建议使用,但因为客户需要考试可能用到,所以又做了一遍 1. 配置受管Server,ProxyServer,过程略 2.构建Proxy Application 建立一个ProxyApp的 ...

  4. webpack配置:less/sass文件打包和分离、自动处理css前缀、消除未使用的css及完整的webpack.config.js文件

    一.less文件打包和分离 1.要使用less,首先使用npm安装less服务:还需要安装Less-loader用来打包使用. npm install less --save-dev npm inst ...

  5. java源码阅读LinkedBlockingQueue

    1类签名与简介 public class LinkedBlockingQueue<E> extends AbstractQueue<E> implements Blocking ...

  6. 通过案例对SparkStreaming透彻理解三板斧之一

    本节课通过二个部分阐述SparkStreaming的理解: 一.解密SparkStreaming另类在线实验 二.瞬间理解SparkStreaming本质 Spark源码定制班主要是自己做发行版.自己 ...

  7. mapreduce实现搜索引擎简单的倒排索引

    使用hadoop版本为2.2.0 倒排索引简单的可以理解为全文检索某个词 例如:在a.txt 和b.txt两篇文章分别中查找统计hello这个单词出现的次数,出现次数越多,和关键词的吻合度就越高 现有 ...

  8. uva 10934 装满水的气球

    题意和思路见: http://blog.csdn.net/shuangde800/article/details/11273123 我的想法: 首先问题转化一下 将问题转化成:定义f[i][j] 表示 ...

  9. Android基础新手教程——4.1.2 Activity初窥门径

    Android基础新手教程--4.1.2 Activity初窥门径 标签(空格分隔): Android基础新手教程 本节引言: 上一节中我们对Activity一些主要的概念进行了了解,什么是Activ ...

  10. Android Volley框架的使用(四)图片的三级缓存策略(内存LruCache+磁盘DiskLruCache+网络Volley)

    在开发安卓应用中避免不了要使用到网络图片,获取网络图片很简单,但是需要付出一定的代价——流量.对于少数的图片而言问题不大,但如果手机应用中包含大量的图片,这势必会耗费用户的一定流量,如果我们不加以处理 ...