`
85977328
  • 浏览: 1878290 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

java并发(六)线程安全与共享资源

 
阅读更多
允许被多个线程同时执行的代码称作线程安全的代码。线程安全的代码不包含竞态条件。当多个线程同时更新共享资源时会引发竞态条件。因此,了解Java线程执行时共享了什么资源很重要。

局部变量
局部变量存储在线程自己的栈中。也就是说,局部变量永远也不会被多个线程共享。所以,基础类型的局部变量是线程安全的。下面是基础类型的局部变量的一个例子:
public void someMethod(){
  long threadSafeInt = 0;
  threadSafeInt++;
}


局部的对象引用
对象的局部引用和基础类型的局部变量不太一样。尽管引用本身没有被共享,但引用所指的对象并没有存储在线程的栈内。所有的对象都存在共享堆中。如果在某个方法中创建的对象不会逃逸出(译者注:即该对象不会被其它方法获得,也不会被非局部变量引用到)该方法,那么它就是线程安全的。实际上,哪怕将这个对象作为参数传给其它方法,只要别的线程获取不到这个对象,那它仍是线程安全的。下面是一个线程安全的局部引用样例:
public void someMethod(){
  LocalObject localObject = new LocalObject();
  localObject.callMethod();
  method2(localObject);
}

public void method2(LocalObject localObject){
  localObject.setValue("value");
}

样例中LocalObject对象没有被方法返回,也没有被传递给someMethod()方法外的对象。每个执行someMethod()的线程都会创建自己的LocalObject对象,并赋值给localObject引用。因此,这里的LocalObject是线程安全的。事实上,整个someMethod()都是线程安全的。即使将LocalObject作为参数传给同一个类的其它方法或其它类的方法时,它仍然是线程安全的。当然,如果LocalObject通过某些方法被传给了别的线程,那它就不再是线程安全的了。

对象成员
对象成员存储在堆上。如果两个线程同时更新同一个对象的同一个成员,那这个代码就不是线程安全的。下面是一个样例:
public class NotThreadSafe{
    StringBuilder builder = new StringBuilder();
    public add(String text){
        this.builder.append(text);
    }  
}

如果两个线程同时调用同一个NotThreadSafe实例上的add()方法,就会有竞态条件问题。例如:
NotThreadSafe sharedInstance = new NotThreadSafe();
new Thread(new MyRunnable(sharedInstance)).start();
new Thread(new MyRunnable(sharedInstance)).start();
public class MyRunnable implements Runnable{
  NotThreadSafe instance = null;
  public MyRunnable(NotThreadSafe instance){
    this.instance = instance;
  }
  public void run(){
    this.instance.add("some text");
  }
}

注意两个MyRunnable共享了同一个NotThreadSafe对象。因此,当它们调用add()方法时会造成竞态条件。
当然,如果这两个线程在不同的NotThreadSafe实例上调用call()方法,就不会导致竞态条件。下面是稍微修改后的例子:
new Thread(new MyRunnable(new NotThreadSafe())).start();
new Thread(new MyRunnable(new NotThreadSafe())).start();

现在两个线程都有自己单独的NotThreadSafe对象,调用add()方法时就会互不干扰,再也不会有竞态条件问题了。所以非线程安全的对象仍可以通过某种方式来消除竞态条件。

线程控制逃逸规则
线程控制逃逸规则可以帮助你判断代码中对某些资源的访问是否是线程安全的。

引用
如果一个资源的创建,使用,销毁都在同一个线程内完成,
且永远不会脱离该线程的控制,则该资源的使用就是线程安全的。


资源可以是对象,数组,文件,数据库连接,套接字等等。Java中你无需主动销毁对象,所以“销毁”指不再有引用指向对象。

即使对象本身线程安全,但如果该对象中包含其他资源(文件,数据库连接),整个应用也许就不再是线程安全的了。比如2个线程都创建了各自的数据库连接,每个连接自身是线程安全的,但它们所连接到的同一个数据库也许不是线程安全的。比如,2个线程执行如下代码:

引用
检查记录X是否存在,如果不存在,插入X

如果两个线程同时执行,而且碰巧检查的是同一个记录,那么两个线程最终可能都插入了记录:

引用
线程1检查记录X是否存在。检查结果:不存在
线程2检查记录X是否存在。检查结果:不存在
线程1插入记录X
线程2插入记录X

同样的问题也会发生在文件或其他共享资源上。因此,区分某个线程控制的对象是资源本身,还是仅仅到某个资源的引用很重要。
分享到:
评论
2 楼 85977328 2014-06-27  
laj12347 写道
public class NotThreadSafe{
   
    public add(String text){
        StringBuilder builder = new StringBuilder();
        builder.append("00");
        builder.append("00");
        .............

        builder.append(text);
    } 
}


这种局部变量是不是就不用考虑线程安全的问题了。虽然StringBuilder  不是线程安全你的,还有如果把StringBuilder 换成Stringbuffer是不是上面的问题也就不是问题了。

没错,局部变量是安全的。而且性能会更好
1 楼 laj12347 2014-06-27  
public class NotThreadSafe{
   
    public add(String text){
        StringBuilder builder = new StringBuilder();
        builder.append("00");
        builder.append("00");
        .............

        builder.append(text);
    } 
}


这种局部变量是不是就不用考虑线程安全的问题了。虽然StringBuilder  不是线程安全你的,还有如果把StringBuilder 换成Stringbuffer是不是上面的问题也就不是问题了。

相关推荐

    Java多线程与并发库高级应用视频教程22集

    Java多线程与并发库高级应用视频教程22集资源目录:【】01传统线程技术回顾【】02传统定时器技术回顾【】03传统线程互斥技术【】04传统线程同步通信技术【】04传统线程同步通信技术_分割纪录【】05线程范围内共享...

    java并发编程:线程基础

    线程的同步与阻塞: 引入多线程访问共享资源可能导致的问题,如竞态条件和数据不一致。介绍如何使用 synchronized 关键字来实现线程的同步和阻塞。 线程间通信: 详解线程间通信的方法,包括 wait、notify 和 ...

    java多线程安全性基础介绍.pptx

    java多线程安全性基础介绍 线程安全 正确性 什么是线程安全性 原子性 竞态条件 i++ 读i ++ 值写回i 可见性 JMM 由于cpu和内存加载速度的差距,在两者之间增加了多级缓存导致,内存并不能直接对cpu可见。 ...

    92道Java多线程与并发面试题含答案(很全)

    Java并发编程的核心概念包括: 线程(Thread):线程是程序执行流的最小单元。一个进程可以有一个或多个线程,每个线程都执行其自己的任务。 进程(Process):进程是操作系统分配资源(如内存)和调度的单位。一个...

    java+并发编程实战+资源合集

    在多线程编程中最重要的就是对共享资源的并发访问。如何能安全,高效,互不干扰的让各个线程稳定运行成为多线程编程中的关键。 Java并发编程是基于多线程技术的一种编程技术,该技术是为了解决资源利用率、响应速度...

    java多线程设计模式详解(PDF及源码)

    (注意,本资源附带书中源代码可供参考) 多线程与并发处理是程序设计好坏优劣的重要课题,本书通过浅显易懂的文字与实例来介绍Java线程相关的设计模式概念,并且通过实际的Java程序范例和 UML图示来一一解说,书中...

    14个Java线程并发面试题和答案..pdf

    答案:线程同步是指在多个线程访问共享资源时,防止线程之间的干扰和数据不一致性的机制。 知识点:线程同步的定义、共享资源、数据一致性。 4. 问题:Java中的同步机制有哪些? 答案:Java中的同步机制包括:...

    Java并发编程(学习笔记).xmind

    事件处理器与访问共享状态的其他代码都要采取线程安全的方式实现 框架通过在框架线程中调用应用程序代码将并发性引入应用程序,因此对线程安全的需求在整个应用程序中都需要考虑 基础知识 线程安全性 ...

    高并发之-SimpleDateFormat类的线程安全问题和解决方案.docx

    缓存机制使用了一个缓存数组来存储解析和格式化的结果,但是这个缓存数组是共享的,这意味着在多线程环境中,多个线程可能会同时访问和修改这个缓存数组,导致线程安全问题。 重现SimpleDateFormat类的线程安全问题...

    Java并发编程实战

    本书深入浅出地介绍了Java线程和并发,是一本完美的Java并发参考手册。书中从并发性和线程安全性的基本概念出发,介绍了如何使用类库提供的基本并发构建块,用于避免并发危险、构造线程安全的类及验证线程安全的规则...

    java应用程序中使用线程

    3.1 Java线程 3.2 创建线程 3.3 使用线程的缺点 3.3.1 初始启动变慢 3.3.2 资源利用 3.3.2 资源利用 3.4 线程管理 3.5 共享资源的使用同步 3.5.1 同步方法和同步代码块的嵌套调用...

    解析Java的多线程机制

    而Java应用程序中的多线程则是共享同一应用系统资源的多个并行代码执行 体,线程之间的通信和协调方法相对简单。 可以说:Java语言对应用程序多线程能力的支持增强了Java作为网络程序设计语言的优势,为实现分布式...

    java高并发的解决方案

    高并发意味着多个线程同时访问共享资源,因此需要确保数据的安全性。可以使用线程安全的数据结构或实现自己的线程安全机制,如使用锁(分布式锁、读写锁、乐观锁、悲观锁)、同步代码块等。 八、限流与熔断 在高...

    Java 并发编程实战_2012

    【描述】Java 并发编程实战_2012,主J要讲解并发编程相关的知识点,Java中的多线程部分以及并发处理的相关内容。 【版权声明】该资源应用与共享和交流学习,不作它用。如有侵权,请联系删除 【资源说明】改版后不能...

    Java高并发编程详解:多线程与架构设计 (Java核心技术系列)

    部分主要阐述Thread的基础知识,详细介绍线程的API使用、线程安全、线程间数据通信,以及如何保护共享资源等内容,它是深入学习多线程内容的基础。 第二部分引入了ClassLoader,这是因为ClassLoader与线程不无关系,...

    Java并发编程最全面试题 123道.pdf

    线程之间对共享资源的访问会相互影响,必须解决竞用共享资源的问题。 十、线程和进程的区别 * 进程:一个在内存中运行的应用程序。 * 线程:进程中的一个执行任务(控制单元),负责在程序里独立执行。 十一、...

    java并发编程理论基础精讲

    共享资源与竞态条件: 详解共享资源在多线程环境中的问题,引出竞态条件的概念。 对象锁和监视器: 介绍对象锁的概念,解释如何使用 synchronized 关键字来实现对象级别的同步。 线程间通信: 详细讲解多线程之间...

    java学习多线程处理

    线程与父进程的其他线程共享进程所有的全部资源。 独立运行,采用独占方式。 一个线程可以创建和删除另外一个线程。 同一个进程中的多个线程之间可以并发执行。 线程的调度管理是由进程来完成的。 注意:编程...

    java 线程安全 是程序执行流的最小单元

    另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消...

    Java 软件设计基础:Java线程机制

    它与父进程的其他线程共享该进程拥有的全部资源。 多线程 多线程指在单个程序中可以同时运行多个不同的线程,执行不同的任务。这是实现并发机制的一种有效手段。操作系统使用分时管理各个进程,按时间片轮流执行每...

Global site tag (gtag.js) - Google Analytics