`
itwangxinli
  • 浏览: 143520 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论
阅读更多

Java多线程同步问题的探究(一、线程的先来后到)

众所周知,在Java多线程编程中,一个非常重要的方面就是线程的同步问题。
关于线程的同步,一般有以下解决方法:

1. 在需要同步的方法的方法签名中加入synchronized关键字。

2. 使用synchronized块对需要进行同步的代码段进行同步。

3. 使用JDK 5中提供的java.util.concurrent.lock包中的Lock对象。

另外,为了解决多个线程对同一变量进行访问时可能发生的安全性问题,我们不仅可以采用同步机制,更可以通过JDK 1.2中加入的ThreadLocal来保证更好的并发性。

本篇中,将详细的讨论Java多线程同步机制,并对ThreadLocal做出探讨。

大致的目录结构如下:

一、线程的先来后到——问题的提出:为什么要有多线程同步?Java多线程同步的机制是什么?
二、给我一把锁,我能创造一个规矩——传统的多线程同步编程方法有哪些?他们有何异同?
三、Lock来了,大家都让开—— Java并发框架中的Lock详解。
四、协作,互斥下的协作——Java多线程协作(wait、notify、notifyAll)
五、你有我有全都有—— ThreadLocal如何解决并发安全性?
六、总结——Java线程安全的几种方法对比。


一、线程的先来后到

我们来举一个Dirty的例子:某餐厅的卫生间很小,几乎只能容纳一个人如厕。为了保证不受干扰,如厕的人进入卫生间,就要锁上房门。我们可以把卫生间想象
成是共享的资源,而众多需要如厕的人可以被视作多个线程。假如卫生间当前有人占用,那么其他人必须等待,直到这个人如厕完毕,打开房门走出来为止。这就好比多个线程共享一个资源的时候,是一定要分出先来后到的。

有人说:那如果我没有这道门会怎样呢?让两个线程相互竞争,谁抢先了,谁就可以先干活,这样多好阿?但是我们知道:如果厕所没有门的话,如厕的人一起涌向厕所,那么必然会发生争执,正常的如厕步骤就会被打乱,很有可能会发生意想不到的结果,例如某些人可能只好被迫在不正确的地方施肥……
正是因为有这道门,任何一个单独进入如厕的人都可以顺利的完成他们的如厕过程,而不会被干扰,甚至发生以外的结果。这就是说,如厕的时候要讲究先来后到。
转载
那么在Java 多线程程序当中,当多个线程竞争同一个资源的时候,如何能够保证他们不会产生“打架”的情况呢?有人说是使用同步机制。没错,像上面这个例子,就是典型的同步案例,一旦第一位开始如厕,则第二位必须等待第一位结束,才能开始他的如厕过程。一个线程,一旦进入某一过程,必须等待正常的返回,并退出这一过程,下一个线程才能开始这个过程。这里,最关键的就是卫生间的门。其实,卫生间的门担任的是资源锁的角色,只要如厕的人锁上门,就相当于获得了这个锁,而当他打开锁出来以后,就相当于释放了这个锁。

也就是说,多线程的线程同步机制实际上是靠锁的概念来控制的。那么在Java程序当中,锁是如何体现的呢?


让我们从JVM的角度来看看锁这个概念:

在Java程序运行时环境中,JVM需要对两类线程共享的数据进行协调:
1)保存在堆中的实例变量
2)保存在方法区中的类变量

这两类数据是被所有线程共享的。
(程序不需要协调保存在Java 栈当中的数据。因为这些数据是属于拥有该栈的线程所私有的。)

在java虚拟机中,每个对象和类在逻辑上都是和一个监视器相关联的。
对于对象来说,相关联的监视器保护对象的实例变量。

对于类来说,监视器保护类的类变量。
(如果一个对象没有实例变量,或者一个类没有变量,相关联的监视器就什么也不监视。)
为了实现监视器的排他性监视能力,java虚拟机为每一个对象和类都关联一个锁。代表任何时候只允许一个线程拥有的特权。线程访问实例变量或者类变量不需锁。

但是如果线程获取了锁,那么在它释放这个锁之前,就没有其他线程可以获取同样数据的锁了。(锁住一个对象就是获取对象相关联的监视器)

类锁实际上用对象锁来实现。当虚拟机装载一个class文件的时候,它就会创建一个java.lang.Class类的实例。当锁住一个对象的时候,实际上锁住的是那个类的Class对象。

一个线程可以多次对同一个对象上锁。对于每一个对象,java虚拟机维护一个加锁计数器,线程每获得一次该对象,计数器就加1,每释放一次,计数器就减1,当计数器值为0时,锁就被完全释放了。
java编程人员不需要自己动手加锁,对象锁是java虚拟机内部使用的。

在java程序中,只需要使用synchronized块或者synchronized方法就可以标志一个监视区域。当每次进入一个监视区域时,java虚拟机都会自动锁上对象或者类。
看到这里,我想你们一定都疲劳了吧?o(∩_∩)o...哈哈。让我们休息一下,但是在这之前,请你们一定要记着:

当一个有限的资源被多个线程共享的时候,为了保证对共享资源的互斥访问,我们一定要给他们排出一个先来后到。而要做到这一点,对象锁在这里起着非常重要的作用。如果你想知道更多细节,请接着看本系列的第二篇吧。
分享到:
评论

相关推荐

    cpp-RTThread一个嵌入式设备的开源实时操作系统

    RT-Thread一个嵌入式设备的开源实时操作系统

    RT-Thread一个来自中国的开源物联网操作系统它提供了非常强的可伸缩能力

    RT-Thread是一个来自中国的开源物联网操作系统,它提供了非常强的可伸缩能力:从一个可以运行在ARM Cortex-M0芯片上的极小内核,到中等的ARM Cortex-M3/4/7系统,甚至是多核,64位的ARM Cortex-A,MIPS32/64处理器的...

    ThreadX中文学习手册

    第一章 ThreadX 概述及其与嵌入式实时系统的关系。 第二章 安装步骤及使用事项。 第三章 详细介绍高性能实时内核——ThreadX 的功能操作。 第四章 详细介绍ThreadX 应用程序的接口。 第五章 介绍ThreadX 应用程序的...

    关于C#中Thread.Join()的一点理解

    是第一次在C#中接触Thread,自己研究了一下其中Thread.Join()这个方法,下面谈谈自己的理解。  Thread.Join()在MSDN中的解释很模糊:Blocks the calling thread until a thread terminates  有两个主要问题: ...

    java Thread

    创建一个站台类Station,继承Thread,重写run方法,在run方法里面执行售票操作!售票要使用同步锁:即有一个站台卖这张票时,其他站台要等这张票卖完! 2.创建主方法调用类 里面有源码,导入myeclipse执行

    AT32F435移植THreadX;AT32F437移植THreadX,移植最新版THreadX

    依照雅特力官方移植说明,移植下来,编译一堆警告和错误。 经过2天努力,终于移植成功。开发工具采用MDK5.38。实验板采用雅特力的AT_START_F437。 项目中打开了2个线程,通过tx_mutex_get互斥操作,来输出print字符...

    这是一个线程类(Thread

    Thread对初学者有很大的帮助,有线程(Thread)的继承,Runner的实现的区别。

    Java 的线程工厂 ThreadFactory原理及源码详解

    在JDK的源码使用工厂模式,ThreadFactory就是其中一种。 在我们一般的使用中,创建一个线程,通常有两种方式: 继承Thread类,覆盖run方法,实现我们需要的业务 继承Runnable接口,实现run方法,实现我们需要的业务,...

    实时操作系统ThreadX剖析

    本文讲述了threadX rtos,是一个实时系统, 多线程.

    Thread Factory ActiveX控件

    Thread Factory ActiveX控件 是一个为了轻松地创建robust Multi-Threaded Visual Basic 6 和VBA应用程序和工具的DLL工具库。Thread Factory能够使Visual Basic程序员有能力创建运行在分别thread的COM对象。...

    rt-thread源码

    RT-Thread实时操作系统是一个分层的操作系统,它包括了: 底层移植、驱动层,这层与硬件密切相关,由Drivers和CPU移植相构成。 硬实时内核,这层是RT-Thread的核心,包括了内核系统中对象的实现,例如多线程及其...

    win32 thread封装cthread

    最近,我的兄弟问我是否有...为了支持新的类,CThread,其他支持类也同时研发。这些国家包括CMutexClass,CEventClass和CTask类。在CMutexClass和CEventClass提供资源管理,而CTask类是派生类支持同质异步线程的基类。

    Qt的MoveToThread显示无法关闭在另一个线程的定时器

    2就是MovetoThread方法; 目的:第二种方法有其独特的用法,就是可以做成任务槽的方式,做完任务就返回,然后exec进入事件循环,可以避免单一任务频繁创建线程的开销,又可以达到在另一个线程中进行任务的执行; ...

    boost—thread教程

    (1)thread():构造一个表示当前执行线程的线程对象; (2)explicit thread(const boost::function0& threadfunc): boost::function0可以简单看为:一个无返回(返回void),无参数的函数。这里的函数也可以是类...

    一起来学RT-Thread教程连载

    一起来学RT-Thread教程连载:非常有用的RT-Thread教程,有非常详细的讲解,结合指南看更是收获很多。觉得不错不妨评论一下,谢谢!

    Android:Handler的post()方法和Thread的start()方法执行Thread的run()方法的区别

    * 创建一个Handler对象,使用Handler对象h把Runnable的对象r压入队列 * 此时只会会执行Run()方法,但是不会开启新的线程 */ //Handler h = new Handler(); //h.post(r); /* * 在java中真正开启...

    RT-Thread Studio-v2.2.6-setup-x86-64-202305191040

    RT-Thread,全称是 Real Time-Thread,顾名思义,它是一个嵌入式实时多线程操作系统,基本属性之一是支持多任务,允许多个任务同时运行并不意味着处理器在同一时刻真地执行了多个任务。事实上,一个处理器核心在某一...

    各种 Java Thread State 第一分析法则 - 旁观者 - 博客园

    各种 Java Thread State 第一分析法则

    RT-Thread最全入门教程

    RT-Thread是一个实时的内核(全抢占优先级调度,调度器时间复杂度O(1)),但在发展过程中,RT-Thread实时操作系统得到了来自全国嵌入式开发工程师的鼎力支持,为RT-Thread添砖加瓦,现在它不仅仅是一款高效、稳定的...

    详解C++ thread用法总结

    1,简介 C++11中加入了<thread>头文件,此头文件主要声明了std::thread线程类。C++11的标准类std::thread...检查thread对象是否标识一个活动(active)的可行性线程。缺省构造的thread对象、已经完成join的thread对象、已

Global site tag (gtag.js) - Google Analytics