`

多线程并发访问解决方案

 
阅读更多
synchronized关键字主要解决多线程共享数据同步问题。
ThreadLocal使用场合主要解决多线程中数据因并发产生不一致问题。
ThreadLocal和Synchonized都用于解决多线程并发访问。但是ThreadLocal与synchronized有本质的区别。synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反,它用于在多个线程间通信时能够获得数据共享。
Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。
当然ThreadLocal并不能替代synchronized,它们处理不同的问题域。Synchronized用于实现同步机制,比ThreadLocal更加复杂。

l         java中synchronized用法
       使用了synchronized关键字可以轻松地解决多线程共享数据同步问题。
synchronized关键字可以作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句块。如果再细的分类,synchronized可作用于instance变量、object reference(对象引用)、static函数和class literals(类名称字面常量)身上。
       synchronized取得的锁都是对象;每个对象只有一个锁(lock)与之相关联;实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。

synchronized的4种用法
1.      方法声明时使用,线程获得的是成员锁.
2.      对某一代码块使用,synchronized后跟括号,括号里是变量,线程获得的是成员锁.
3.synchronized后面括号里是一对象,此时,线程获得的是对象锁.
4.synchronized后面括号里是类,此时,线程获得的是对象锁.

synchronized的使用还是有一些细节问题要注意的。

      1.synchronized与static synchronized 的区别
      synchronized是对类的当前实例进行加锁,防止其他线程同时访问该类的该实例的所有synchronized块,注意这里是“类的当前实例”,类的两个不同实例就没有这种约束了。那么static synchronized恰好就是要控制类的所有实例的访问了,static synchronized是限制线程同时访问jvm中该类的所有实例同时访问对应的代码快。实际上,在类中某方法或某代码块中有synchronized,那么在生成一个该类实例后,改类也就有一个监视快,放置线程并发访问改实例synchronized保护快,而static synchronized则是所有该类的实例公用一个监视快了,也也就是两个的区别了,也就是synchronized相当于this.synchronized,而
static synchronized相当于Something.synchronized.
      一个日本作者-结成浩的《java多线程设计模式》有这样的一个列子:
      pulbic class Something(){
         public synchronized void isSyncA(){}
         public synchronized void isSyncB(){}
         public static synchronized void cSyncA(){}
         public static synchronized void cSyncB(){}
     }
   那么,加入有Something类的两个实例a与b,那么下列组方法何以被1个以上线程同时访问呢
   a.   x.isSyncA()与x.isSyncB()
   b.   x.isSyncA()与y.isSyncA()
   c.   x.cSyncA()与y.cSyncB()
   d.   x.isSyncA()与Something.cSyncA()
    这里,很清楚的可以判断:
   a,都是对同一个实例的synchronized域访问,因此不能被同时访问
   b,是针对不同实例的,因此可以同时被访问
   c,因为是static synchronized,所以不同实例之间仍然会被限制,相当于Something.isSyncA()与   Something.isSyncB()了,因此不能被同时访问。
   那么,第d呢?,书上的答案是可以被同时访问的,答案理由是synchronzied的是实例方法与synchronzied的类方法由于锁定(lock)不同的原因。
   个人分析也就是synchronized 与static synchronized 相当于两帮派,各自管各自,相互之间就无约束了,可以被同时访问。目前还不是分清楚java内部设计synchronzied是怎么样实现的。

    结论:A: synchronized static是某个类的范围,synchronized static cSync{}防止多个线程同时访问这个    类中的synchronized static 方法。它可以对类的所有对象实例起作用。
 
               B: synchronized 是某实例的范围,synchronized isSync(){}防止多个线程同时访问这个实例中的synchronized 方法。


     2.synchronized方法与synchronized代码快的区别
     假设P1、P2是同一个类的不同对象,这个类中定义了以下几种情况的同步块或同步方法,P1、P2就都能够调用他们。
Java的synchronized使用方法总结
1.  把synchronized当作函数修饰符时,示例代码如下:
Public synchronized void method(){  
//….  

这也就是同步方法,那这时synchronized锁定的是哪个对象呢?他锁定的是调用这个同步方法对象。也就是说,当一个对象P1在不同的线程中执行这个同步方法时,他们之间会形成互斥,达到同步的效果。但是这个对象所属的Class所产生的另一对象P2却能够任意调用这个被加了synchronized关键字的方法。
上边的示例代码等同于如下代码:
public void method()  
{  
synchronized (this)      //  (1)  
{  
       //…..  
}  
}  
(1)处的this指的是什么呢?他指的就是调用这个方法的对象,如P1。可见同步方法实质是将synchronized作用于object reference。――那个拿到了P1对象锁的线程,才能够调用P1的同步方法,而对P2而言,P1这个锁和他毫不相干,程式也可能在这种情形下摆脱同步机制的控制,造成数据混乱。
2.同步块,示例代码如下:
public void method(SomeObject so) {  
synchronized(so)  
{  
       //…..  
}  
}  
这时,锁就是so这个对象,谁拿到这个锁谁就能够运行他所控制的那段代码。当有一个明确的对象作为锁时,就能够这样写程式,但当没有明确的对象作为锁,只是想让一段代码同步时,能够创建一个特别的instance变量(他得是个对象)来充当锁:
class Foo implements Runnable  
{  
       private byte[] lock = new byte[0];  // 特别的instance变量  
    Public void method()  
{  
       synchronized(lock) { //… }  
}  
//…..  
}  
注:零长度的byte数组对象创建起来将比任何对象都经济――查看编译后的字节码:生成零长度的byte[]对象只需3条操作码,而Object lock = new Object()则需要7行操作码。
3.将synchronized作用于static 函数,示例代码如下:
      Class Foo  
{  
public synchronized static void method1()   // 同步的static 函数  
{  
//….  
}  
public void method2()  
{  
       synchronized(Foo.class)   //  class literal(类名称字面常量)  
}  
       }  

代码中的method2()方法是把class literal作为锁的情况,他和同步的static函数产生的效果是相同的,取得的锁很特别,是当前调用这个方法的对象所属的类(Class,而不再是由这个Class产生的某个具体对象了)。
记得在《Effective Java》一书中看到过将 Foo.class和 P1.getClass()用于作同步锁还不相同,不能用P1.getClass()来达到锁这个Class的目的。P1指的是由Foo类产生的对象。
能够推断:假如一个类中定义了一个synchronized的static函数A,也定义了一个synchronized 的instance函数B,那么这个类的同一对象Obj在多线程中分别访问A和B两个方法时,不会构成同步,因为他们的锁都不相同。A方法的锁是Obj所属的那个Class,而B的锁是Obj所属的这个对象。
Java的synchronized使用方法小结如下:
搞清楚synchronized锁定的是哪个对象,就能帮助我们设计更安全的多线程程式。
更有一些技巧能够让我们对共享资源的同步访问更加安全:
1.  定义private 的instance变量+他的 get方法,而不要定义public/protected的instance变量。假如将变量定义为public,对象在外界能够绕过同步方法的控制而直接取得他,并改变他。这也是JavaBean的标准实现方式之一。
2.  假如instance变量是个对象,如数组或ArrayList什么的,那上述方法仍然不安全,因为当外界对象通过get方法拿到这个instance对象的引用后,又将其指向另一个对象,那么这个private变量也就变了,岂不是很危险。这个时候就需要将get方法也加上synchronized同步,并且,只返回这个private对象的clone()――这样,调用端得到的就是对象副本的引用了。


l         java.lang.ThreadLocal()的用法
一、概述
ThreadLocal是什么呢?其实ThreadLocal并非是一个线程的本地实现版本,它并不是一个Thread,而是threadlocalvariable(线程局部变量)。也许把它命名为ThreadLocalVar更加合适。线程局部变量(ThreadLocal)其实的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,是Java中一种较为特殊的线程绑定机制,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。
ThreadLocal是如何做到为每一个线程维护变量的副本的呢?其实实现的思路很简单,在ThreadLocal类中有一个Map,用于存储每一个线程的变量的副本。
概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。
二、API说明
ThreadLocal()
创建一个线程本地变量。
T get()
返回此线程局部变量的当前线程副本中的值,如果这是线程第一次调用该方法,则创建并初始化此副本。
protected T initialValue()
返回此线程局部变量的当前线程的初始值。最多在每次访问线程来获得每个线程局部变量时调用此方法一次,即线程第一次使用 get() 方法访问变量的时候。如果线程先于 get 方法调用 set(T) 方法,则不会在线程中再调用 initialValue 方法。
若该实现只返回 null;如果程序员希望将线程局部变量初始化为 null 以外的某个值,则必须为 ThreadLocal 创建子类,并重写此方法。通常,将使用匿名内部类。initialValue 的典型实现将调用一个适当的构造方法,并返回新构造的对象。
void remove()
移除此线程局部变量的值。这可能有助于减少线程局部变量的存储需求。如果再次访问此线程局部变量,那么在默认情况下它将拥有其 initialValue。
void set(T value)
将此线程局部变量的当前线程副本中的值设置为指定值。许多应用程序不需要这项功能,它们只依赖于 initialValue() 方法来设置线程局部变量的值。
在程序中一般都重写initialValue方法,以给定一个特定的初始值。
三、典型实例
四、总结
ThreadLocal使用场合主要解决多线程中数据因并发产生不一致问题。
    ThreadLocal为每个线程的中并发访问的数据提供一个副本,通过访问副本来运行业务,这样的结果是耗费了内存,单大大减少了线程同步所带来性能消耗,也减少了线程并发控制的复杂度。
ThreadLocal不能使用原子类型,只能使用Object类型。ThreadLocal的使用比synchronized要简单得多。
五、ThreadLocal使用的一般步骤
1、在多线程的类(如ThreadDemo类)中,创建一个ThreadLocal对象threadXxx,用来保存线程间需要隔离处理的对象xxx。
2、在ThreadDemo类中,创建一个获取要隔离访问的数据的方法getXxx(),在方法中判断,若ThreadLocal对象为null时候,应该new()一个隔离访问类型的对象,并强制转换为要应用的类型。
3、在ThreadDemo类的run()方法中,通过getXxx()方法获取要操作的数据,这样可以保证每个线程对应一个数据对象,在任何时刻都操作的是这个对象。
分享到:
评论

相关推荐

    Java多线程并发访问解决方案

    NULL 博文链接:https://271072008-qq-com.iteye.com/blog/1086373

    Java多线程并发相关资料汇总

    资源名称:Java多线程并发相关资料汇总   资源目录: ... 【】Java多线程并发访问解决方案 【】java多线程详解 【】linkable 资源太大,传百度网盘了,链接在附件中,有需要的同学自取。

    javaweb高并发量网站解决方案

    大型网站,比如门户网站,在面对大量用户访问、高并发请求方面,基本的解决方案集中在这样几个环节:使用高 性能的服务器、高性能的数据库、高效率的编程语言、还有高性能的Web容器。这几个解决思路在一定程度上意味...

    java多线程编程_java多线程_

    2.讲解了在多线程中对并发访问的控制, 主要就是synchronized的使用, 由于此关键字在使用上非常灵活, 所以书中用了很多案例来介绍此关键字的使用, 为读者学习同步相关内容打好坚实的基础。3.介绍线程并不是孤独的...

    python 多线程死锁问题的解决方案

    就是当多线程访问多个锁的时候,不同的锁被不同的线程持有,它们都在等待其他线程释放出锁来,于是便陷入了永久等待。比如A线程持有1号锁,等待2号锁,B线程持有2号锁等待1号锁,那么它们永远也等不到执行的那天,...

    易语言-HP-socket扩展 并发许可 解决方案

    如果没有并发许可,用户的访问日志是无法做到准确记录的,因为多线程写入的原因,注定了日志的记录会丢失。为了最大程度的提高并发效率。我们需要为单用户每次分配到的许可证都是一样的编号。这样才可以不影响其他...

    Windows-Programming:主要基于多线程并发和Win APIs的Windows编程练习

    主要基于多线程并发和Win APIs的Windows编程练习 varoius 实验室的目的和功能在 txt 文件中显示,这些文件可以在存储库的根目录中找到。 浏览实验室的文件夹以访问 Source.cpp 文件。 这些文件夹是从 Visual Studio...

    Python高并发解决方案实现过程详解

    一.cdn加速 简单说就是把静态资源放到别人服务器上 全称:Content Delivery Network或Content Ddistribute Network,...解决因分布、带宽、服务器性能带来的访问延迟问题,适用于站点加速、点播、直播等场景。使用户可

    深入理解Java并发之synchronized实现原理.docx

    因此为了解决这个问题,我们可能需要这样一个方案,当存在多个线程操作共享数据时,需要保证同一时刻有且只有一个线程在操作共享数据,其他线程必须等到该线程处理完数据后再进行,这种方式有个高尚的名称叫互斥锁,...

    精通并发与netty视频教程(2018)视频教程

    29_Gradle插件问题解决方案与Nodejs环境搭建 30_通过gRPC实现Java与Nodejs异构平台的RPC调用 31_gRPC在Nodejs领域中的静态代码生成及与Java之间的RPC通信 32_IO体系架构系统回顾与装饰模式的具体应用 33_Java NIO...

    精通并发与netty 无加密视频

    第29讲:Gradle插件问题解决方案与Nodejs环境搭建 第30讲:通过gRPC实现Java与Nodejs异构平台的RPC调用 第31讲:gRPC在Nodejs领域中的静态代码生成及与Java之间的RPC调用 第32讲:IO体系架构系统回顾与装饰模式的...

    C#并行编程高级教程:精通.NET 4 Parallel Extensions中文(第2部分)

    5.7 限制资源的并发访问 5.7.1 使用SemaphoreSlim 5.7.2 使用超时和取消 5.7.3 使用 Semaphore 5.8 通过CountdownEvent简化动态fork和join场景 5.9 使用原子操作 5.10 小结 第6章 PLINQ:声明式数据并行 6.1...

    springboot_mongodb

    如果如果业务逻辑强依赖于副本变量,则不适合使用ThreadLocal解决,需要另寻解决方案的局部变量,而不是为了解决共享对象的多线程访问问题。实际上,ThreadLocal根本就不能解决共享对象的多线程访问问题。 每个线程...

    精通并发与 netty 视频教程(2018)视频教程

    27_gRPC双向流式数据通信详解 28_gRPC与Gradle流畅整合及问题解决的完整过程与思考 29_Gradle插件问题解决方案与Nodejs环境搭建 30_通过gRPC实现Java与Nodejs异构平台的RPC调用 31_gRPC在Nodejs领域中的静态代码生成...

    java面试题,180多页,绝对良心制作,欢迎点评,涵盖各种知识点,排版优美,阅读舒心

    【高并发】Java高并发解决方案 148 HTML静态化 149 图片服务器分离 149 数据库集群和库表散列 150 缓存 151 镜像 151 负载均衡 152 【网络】说说你对Http协议和Socket协议的理解 153 http协议 153 Tcp协议 154 ...

    C#并行编程高级教程:精通.NET 4 Parallel Extensions中文(第一部分)

    5.7 限制资源的并发访问 5.7.1 使用SemaphoreSlim 5.7.2 使用超时和取消 5.7.3 使用 Semaphore 5.8 通过CountdownEvent简化动态fork和join场景 5.9 使用原子操作 5.10 小结 第6章 PLINQ:声明式数据并行 6.1 从LINQ...

    C#并行编程高级教程:精通.NET 4 Parallel Extensions中文(第3部分)

    5.7 限制资源的并发访问 5.7.1 使用SemaphoreSlim 5.7.2 使用超时和取消 5.7.3 使用 Semaphore 5.8 通过CountdownEvent简化动态fork和join场景 5.9 使用原子操作 5.10 小结 第6章 PLINQ:声明式数据并行 6.1...

    平台设计方案.docx

    在系统安全性方面,为系统提供保护,保证系统的正常运作:在用户安全性方面,通过安全解决方案来保证供求信息的发布的顺利完成。 平台数据库设计原则 建立完善的数据库结构管理设备的基本参数、运行状态和各种平台...

    平台设计方案.doc

    在系统安全性 方面,为系统提供保护,保证系统的正常运作:在用户安全性方面,通过安全解决方案 来保证供求信息的发布的顺利完成。 平台数据库设计原则 建立完善的数据库结构管理设备的基本参数、运行状态和各种工作...

    Redis上实现分布式锁以提高性能的方案研究

    大部分是解决方案基于DB实现的,Redis为单进程单线程模式,采用队列模式将并发访问变成串行访问,且多客户端对Redis的连接并不存在竞争关系。 项目实践 任务队列用到分布式锁的情况比较多,在将业务逻辑中可以异步...

Global site tag (gtag.js) - Google Analytics