Java多线程编程中易混淆的3个关键字总结

2014-06-09  来源:本站原创  分类:Java  人气:1 

这篇文章主要介绍了Java多线程编程中易混淆的3个关键字总结,本文总结了、volatile、ThreadLocal、synchronized等3个关键字,对这几个容易混淆概念的关键字分别做了讲解,需要的朋友可以参考下

概述

最近在看《ThinKing In Java》,看到多线程章节时觉得有一些概念比较容易混淆有必要总结一下,虽然都不是新的东西,不过还是蛮重要,很基本的,在开发或阅读源码中经常会遇到,在这里就简单的做个总结。

1.volatile

volatile主要是用来在多线程中同步变量。
在一般情况下,为了提升性能,每个线程在运行时都会将主内存中的变量保存一份在自己的内存中作为变量副本,但是这样就很容易出现多个线程中保存的副本变量不一致,或与主内存的中的变量值不一致的情况。
而当一个变量被volatile修饰后,该变量就不能被缓存到线程的内存中,它会告诉编译器不要进行任何移出读取和写入操作的优化,换句话说就是不允许有不同于“主”内存区域的变量拷贝,所以当该变量有变化时,所有调用该变量的线程都会获得相同的值,这就确保了该变量在应用中的可视性(当一个任务做出了修改在应用中必须是可视的),同时性能也相应的降低了(还是比synchronized高)。
但需要注意volatile只能确保操作的是同一块内存,并不能保证操作的原子性。所以volatile一般用于声明简单类型变量,使得这些变量具有原子性,即一些简单的赋值与返回操作将被确保不中断。但是当该变量的值由自身的上一个决定时,volatile的作用就将失效,这是由volatile关键字的性质所决定的。
所以在volatile时一定要谨慎,千万不要以为用volatile修饰后该变量的所有操作都是原子操作,不再需要synchronized关键字了。

2.ThreadLocal

首先ThreadLocal和本地线程没有一毛钱关系,更不是一个特殊的Thread,它只是一个线程的局部变量(其实就是一个Map),ThreadLocal会为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。这样做其实就是以空间换时间的方式(与synchronized相反),以耗费内存为代价,单大大减少了线程同步(如synchronized)所带来性能消耗以及减少了线程并发控制的复杂度。
个人觉得比较典型的例子就是在Android关于Looper的源码中对ThreadLocal的使用,同时也包含了ThreadLocal的基本用法,具体代码如下:

public class Looper {
private static final String TAG = "Looper";

// sThreadLocal.get() will return null unless you've called prepare().
private static final ThreadLocal sThreadLocal = new ThreadLocal(); 

...... 

private static Looper mMainLooper = null; 

...... 

public static final void prepare() {
  if (sThreadLocal.get() != null) {
    throw new RuntimeException("Only one Looper may be created per thread");
  }
  sThreadLocal.set(new Looper());
} 

...... 

public static final void prepareMainLooper() {
  prepare();
  setMainLooper(myLooper()); 

  ...... 

} 

private synchronized static void setMainLooper(Looper looper) {
  mMainLooper = looper;
}
public synchronized static final Looper getMainLooper() {
  return mMainLooper;
} 

...... 

public static final Looper myLooper() {
  return (Looper)sThreadLocal.get();
} 

...... 

}

但需要注意的是,虽然ThreadLocal和Synchonized都用于解决多线程并发访问,ThreadLocal与synchronized还是有本质的区别。synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反,它用于在多个线程间通信时能够获得数据共享。即Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。所以ThreadLocal并不能代替synchronized,Synchronized的功能范围更广(同步机制)。

3.synchronized

synchronized关键字是Java利用锁的机制自动实现的,一般有同步方法和同步代码块两种使用方式。Java中所有的对象都自动含有单一的锁(也称为监视器),当在对象上调用其任意的synchronized方法时,此对象被加锁(一个任务可以多次获得对象的锁,计数会递增),同时在线程从该方法返回之前,该对象内其他所有要调用类中被标记为synchronized的方法的线程都会被阻塞。当然针对每个类也有一个锁(作为类的Class对象的一部分),所以你懂的^.^。
最后需要注意的是synchronized是同步机制中最安全的一种方式,其他的任何方式都是有风险的,当然付出的代价也是最大的。

相关文章
  • Java多线程编程中易混淆的3个关键字总结 2014-06-09

    这篇文章主要介绍了Java多线程编程中易混淆的3个关键字总结,本文总结了.volatile.ThreadLocal.synchronized等3个关键字,对这几个容易混淆概念的关键字分别做了讲解,需要的朋友可以参考下 概述 最近在看<ThinKing In Java>,看到多线程章节时觉得有一些概念比较容易混淆有必要总结一下,虽然都不是新的东西,不过还是蛮重要,很基本的,在开发或阅读源码中经常会遇到,在这里就简单的做个总结. 1.volatile volatile主要是用来在多线程中同步变量.

  • C#多线程编程中的锁系统(二) 2014-02-24

    这篇文章主要介绍了C#多线程编程中的锁系统(二),本文讲解了volatile.Interlocked.ReaderWriterLockSlim等升级锁和原子操作的使用实例,需要的朋友可以参考下 上章主要讲排他锁的直接使用方式.但实际当中全部都用锁又太浪费了,或者排他锁粒度太大了. 这一次我们说说升级锁和原子操作. 目录 1:volatile 2: Interlocked 3:ReaderWriterLockSlim 4:总结 一:volatile 简单来说: volatile关键字是告诉c#编译

  • Java多线程编程模式实战指南(三):Two-phase Termination模式 2014-12-01

    停止线程是一个目标简单而实现却不那么简单的任务.首先,Java没有提供直接的API用于停止线程.此外,停止线程时还有一些额外的细节需要考虑,如待停止的线程处于阻塞(等待锁)或者等待状态(等待其它线程).尚有未处理完的任务等.本文介绍的Two-phase Termination模式提供了一种通用的用于优雅地停止线程的方法. Two-phase Termination模式简介 Java并没有提供直接的API用于停止线程.Two-phase Termination模式通过将停止线程这个动作分解为准备阶

  • Java多线程编程模式实战指南(二):Immutable Object模式 2015-01-15

    多线程共享变量的情况下,为了保证数据一致性,往往需要对这些变量的访问进行加锁.而锁本身又会带来一些问题和开销.Immutable Object模式使得我们可以在不使用锁的情况下,既保证共享变量访问的线程安全,又能避免引入锁可能带来的问题和开销. Immutable Object模式简介 多线程环境中,一个对象常常会被多个线程共享.这种情况下,如果存在多个线程并发地修改该对象的状态或者一个线程读取该对象的状态而另外一个线程试图修改该对象的状态,我们不得不做一些同步访问控制以保证数据一致性.而这些同

  • Java并发编程中构建自定义同步工具 2015-02-09

    这篇文章主要介绍了Java并发编程中构建自定义同步工具,本文讲解了可阻塞状态依赖操作的结构.有界缓存实现基类示例.阻塞实现方式一:抛异常给调用者.阻塞实现方式二:通过轮询和休眠.阻塞实现方式三:条件队列等内容,需要的朋友可以参考下 当Java类库没有提供适合的同步工具时,就需要构建自定义同步工具. 可阻塞状态依赖操作的结构 acquir lock on object state;//请求获取锁 while(precondition does not hold){//没有满足前提条件 releas

  • Java多线程编程(1)-Thread和Runnable 2015-03-25

    1.概念和示例代码 进程是内存中运行的一个应用程序,是操作系统分配资源的最小单位. 线程是进程中的一个执行流程,进程可以执行多个线程,线程总是属于某个进程,进程中的多个线程共享进程中的内存资源. 为了更有效的完成任务和利用CPU资源,需要多线程操作,因而需要多线程编程.Java多线程编程的时候,可以继承于Thread对象,也可以实现Runnable接口. 示例代码如下. public class Main { public static void main(String[] args) { //

  • C#多线程编程中的锁系统(四):自旋锁 2014-03-15

    这篇文章主要介绍了C#多线程编程中的锁系统(四):自旋锁,本文讲解了基础知识.自旋锁示例.SpinLock等内容,需要的朋友可以参考下 目录一:基础 二:自旋锁示例 三:SpinLock 四:继续SpinLock 五:总结 一:基础 内核锁:基于内核对象构造的锁机制,就是通常说的内核构造模式.用户模式构造和内核模式构造 优点:cpu利用最大化.它发现资源被锁住,请求就排队等候.线程切换到别处干活,直到接受到可用信号,线程再切回来继续处理请求. 缺点:托管代码->用户模式代码->内核代码损耗.线

  • python多线程编程中的join函数使用心得 2014-04-15

    这篇文章主要介绍了python多线程编程中的join函数使用心得,本文先是给出了join函数使用例子,并对join函数的使用作了总结,需要的朋友可以参考下 今天去辛集买箱包,下午挺晚才回来,又是恶心又是头痛.恶心是因为早上吃坏东西+晕车+回来时看到车祸现场,头痛大概是烈日和空调混合刺激而成.没有时间没有精神没有力气学习了,这篇博客就说说python中一个小小函数. 由于坑爹的学校坑爷的专业,多线程编程老师从来没教过,多线程的概念也是教的稀里糊涂,本人python也是菜鸟级别,所以遇到多线程的编程

  • C#多线程编程中的锁系统基本用法 2014-06-04

    这篇文章主要介绍了C#多线程编程中的锁系统基本用法,本文讲解了lock.Monitor.mutex.Semaphore等内容,需要的朋友可以参考下 平常在多线程开发中,总避免不了线程同步.本篇就对net多线程中的锁系统做个简单描述. 目录 一:lock.Monitor 1:基础. 2: 作用域. 3:字符串锁. 4:monitor使用 二:mutex 三:Semaphore 四:总结 一:lock.Monitor 1:基础 Lock是Monitor语法糖简化写法.Lock在IL会生成Monito

  • C#多线程编程中的锁系统(三) 2014-07-14

    这篇文章主要介绍了C#多线程编程中的锁系统(三),本本文主要说下基于内核模式构造的线程同步方式.事件.信号量以及WaitHandle.AutoResetEvent.ManualResetEvent等内容,需要的朋友可以参考下 本章主要说下基于内核模式构造的线程同步方式,事件,信号量. 目录 一:理论 二:WaitHandle 三:AutoResetEvent 四:ManualResetEvent 五:总结 一:理论 我们晓得线程同步可分为,用户模式构造和内核模式构造. 内核模式构造:是由wind

  • java多线程编程之捕获子线程异常示例 2014-12-05

    java多线程程序中所有线程都不允许抛出未捕获的checked exception,也就是说各个线程需要自己把自己的checked exception处理掉.但是无法避免的是unchecked exception,也就是RuntimeException,当抛出异常时子线程会结束,但不会影响主线程 通过try catch是无法捕获子线程异常的,Thread对象提供了setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)方法用来

  • Java多线程编程总结 2013-02-21

    下面是Java线程系列博文的一个编目: Java线程:概念与原理 Java线程:创建与启动 Java线程:线程栈模型与线程的变量 Java线程:线程状态的转换 Java线程:线程的同步与锁 Java线程:线程的交互 Java线程:线程的调度-休眠 Java线程:线程的调度-优先级 Java线程:线程的调度-让步 Java线程:线程的调度-合并 Java线程:线程的调度-守护线程 Java线程:线程的同步-同步方法 Java线程:线程的同步-同步块 Java线程:并发协作-生产者消费者模型 Jav

  • java多线程并发中使用Lockers类将多线程共享资源锁定 2015-02-25

    Lockers在多线程编程里面一个重要的概念是锁定,如果一个资源是多个线程共享的,为了保证数据的完整性,在进行事务性操作时需要将共享资源锁定,这样可以保证在做事务性操作时只有一个线程能对资源进行操作,下面看一个示例 package com.yao; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; impor

  • Java多线程编程模式实战指南:Active Object模式(下) 2013-10-06

    Active Object模式的评价与实现考量 Active Object模式通过将方法的调用与执行分离,实现了异步编程.有利于提高并发性,从而提高系统的吞吐率. Active Object模式还有个好处是它可以将任务(MethodRequest)的提交(调用异步方法)和任务的执行策略(Execution Policy)分离.任务的执行策略被封装在Scheduler的实现类之内,因此它对外是不"可见"的,一旦需要变动也不会影响其它代码,降低了系统的耦合性.任务的执行策略可以反映以下一些

  • java多线程编程之慎重使用volatile关键字 2014-05-28

    volatile关键字相信了解Java多线程的读者都很清楚它的作用.volatile关键字用于声明简单类型变量,下面看一下为什么要慎重使用volatile关键字 volatile关键字相信了解Java多线程的读者都很清楚它的作用.volatile关键字用于声明简单类型变量,如int.float.boolean等数据类型.如果这些简单数据类型声明为volatile,对它们的操作就会变成原子级别的.但这有一定的限制.例如,下面的例子中的n就不是原子级别的: package mythread; pub

  • Java多线程编程要点 (一) 2010-04-27

    1. 认识Thread和Runnable Java中实现多线程有两种途径:继承Thread类或者实现Runnable接口.Runnable是接口,建议用接口的方式生成线程,因为接口可以实现多继承,况且Runnable只有一个run方法,很适合继承.在使用Thread的时候只需继承Thread,并且new一个实例出来,调用start()方法即可以启动一个线程. Thread Test = new Thread(); Test.start(); 在使用Runnable的时候需要先new一个实现Run

  • JAVA多线程编程详细记录 2012-11-05

    JAVA多线程机制有两种实现方式: 第一种: 继承Thread类, 实现run()方法. 第二种: 实现Runnable接口. 实例代码: 第一种: public class OntThread extends Thread { public static void main(String[] args) { OntThread tsub = new OntThread(); tsub.start(); try { Thread.sleep(1000); System.out.println("

  • java多线程编程之使用Synchronized关键字同步类方法 2015-01-05

    JAVA中要想解决"脏数据"的问题,最简单的方法就是使用synchronized关键字来使run方法同步,看下面的代码,只要在void和public之间加上synchronized关键字 public synchronized void run() { } 从上面的代码可以看出,只要在void和public之间加上synchronized关键字,就可以使run方法同步,也就是说,对于同一个Java类的对象实例,run方法同时只能被一个线程调用,并当前的run执行完后,才能被其他的线程调

  • java网络编程中向指定URL发送GET POST请求示例 2015-03-28

    这篇文章主要介绍了java向指定URL发送GET POST请求示例,学习JAVA网络编程一定会用到的,大家参考使用吧 import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintWriter; import java.net.HttpURLConnection; import

  • Java多线程编程之限制优先级 2014-03-09

    限制线程优先级和调度 Java 线程模型涉及可以动态更改的线程优先级.本质上,线程的优先级是从 1 到 10 之间的一个数字,数字越大表明任务越紧急.JVM 标准首先调用优先级较高的线程,然后才调用优先级较低的线程.但是,该标准对具有相同优先级的线程的处理是随机的.如何处理这些线程取决于基层的操作系统策略.在某些情况下,优先级相同的线程分时运行:在另一些情况下,线程将一直运行到结束.请记住,Java 支持 10 个优先级,基层操作系统支持的优先级可能要少得多,这样会造成一些混乱.因此,只能将优先