当对象在多线程的环境下访问就会出现多种问题,所以我们的程序应该注意在多线环境下对象的状态安全访问以及修改。
线程限制
当对象的修改和访问都限制在单线程的环境下,就可以不用考虑类是否是线程安全了。而实现线程限制有两种方法:栈限制
和使用threadLocal变量限制
。
栈限制:就是将对象的创建和注销限制在方法内,不能使对象的使用范围逸出方法中。所以对象的创建和回收都会栈中发生,对象不会放在推中,所以对其他对象来说是不可见的。该方法如:
public void someMethod(){
Foo foo = new Foo();
foo.someMethod();
}
这样对象就只会在该线程的栈中创建和回收,它就不会逸出方法的范围内。但如果当该方法返回该对象,该对象就会逸出方法的范围内,就会破坏了栈的限制。
使用threadLocal变量限制:threadLocal提供了get和set方法,为每个使用它的线程维护一份单独的拷贝,所以get方法总是返回由当前执行线程通过set设置的最新值。大多数的web框架都是使用该方法从而使每个请求都有自己对应的对象处理,因此减少了跨线程间访问对象的问题。
以上两种方法都可以将对象的访问和修改限制在单线程中,但是大多线程序都是不可以避免地要在跨线程中访问对象,分两种对象来讨论:不可变对象
和可变对象
不可变对象
不可变对象就是在创建之后对象的状态是不可改变的,该种对象的状态就是它创建时的状态,所以其在多线程环境下也是安全。
可变对象
可变对象在跨线程的环境下,要设计为线程安全的类安全的对它的状态进行操作。
volatile变量和同步
由于java内存模型的关系,在一线程中你对某对象的修改,其他的线程不一定能够看到对该对象状态的修改。而使其他线程可以立即看当前线程对某变量的修改有两种方法:使用volatile变量
和同步
。使用volatile变量和同步的区别主要是volatile变量只保证内存可见性而不能保证竞争条件的安全访问和修改,而同步可以保证这两方面。
对可变对象的状态保护
要设计线程安全类就是要设计如何保护对象的状态而不被破坏。而首先是要弄清楚对象的状态是由什么对象变量决定的,而对这些对象的操作是什么,从而决定该对象的变量应该由那些锁保护,所以最重要的问题是要找保护状态变量。而封装就可以减少问题的复杂性,如果对象的状态变量可以很好地封装在对象内部,就可以由该对象内部锁来保护,如果对象的状态变量逸出了对象的控制范围就应该由该对象自己来保护它的状态的安全访问,从而保证拥有它的对象的线程安全。
例如:
代码1:
public class Foo{
private List list = new ArrayList
public synchronized void removeItemIfPresend(Object o){
if(list.contains(o) ){
list.remove(o)
}
}
}
代码2:
public class Foo{
public List list = new ArrayList
public void removeItemIfPresend(Object o){
synchronized(list){
if(list.contains(o) ){
list.remove(o)
}
}
}
}
在代码1中程序取得对象内部锁就可以保证该对象的状态安全,因为它的状态变量都没有逸出它的范围,而代码2如果是取得对象的锁它也不能保证对象状态的安全,因为list已经逸出它的控制范围内了,所以正确的做法是应该取得list的锁,让它自己保护它的状态,从而达到保护该对象状态的目的,所以在多线程范围内保护可变对象的状态,重要的是要清楚取得谁的锁才能真正地做到保护。
分享到:
相关推荐
java多线程安全性基础介绍 线程安全 正确性 什么是线程安全性 原子性 竞态条件 i++ 读i ++ 值写回i 可见性 JMM 由于cpu和内存加载速度的差距,在两者之间增加了多级缓存导致,内存并不能直接对cpu可见。 ...
.doc 格式 详细解析多线程技术 基础篇 • 怎样创建一个线程 • 受托管的线程与 Windows线程 • 前台线程与后台线程 • 名为BeginXXX和EndXXX的方法是做什么用的 • 异步和多线程有什么关联 WinForm多线程编程...
1.Qt下,多线程使用互斥锁安全访问同一全局变量;2.源码中定义了ThreadA和ThreadB,定义变量后,依次调用函数start()来启动重写的run()函数
为了在多线程环境中安全地共享数据,Delphi提供了同步机制,如TCriticalSection、TMutex和TSemaphore。这些同步对象帮助开发者避免竞态条件和数据冲突,确保线程间的协调访问。 此外,Delphi还支持动态线程变量,...
• 业务逻辑对事务和线程安全的要求 • 计算一下冲突的可能性 • 请多使用lock,少用Mutex Web和IIS • 应用程序池,WebApplication,和线程池之间有什么关系 • Web页面怎么调用异步WebService
重点回顾 练习问题 Introduction 2 多线程程序的评量标准 多线程程序的评量标准 安全性——不损坏对象 生存性——进行必要的处理 复用性——可再利用类 性能——能快速、大量进行处理 评量标准的总结 重点回顾 练习...
14 编写高效的线程安全类 (2) 15 轻松使用线程 同步不是敌人.mht 16 轻松使用线程 减少争用.mht 17 轻松使用线程 不共享有时是最好的.mht 18 适用于 Java 程序员的 CSP,第 1 部分.mht 19 适用于 Java 程序员的...
通过将 MyRunnable 对象传递给 Thread 类的构造方法,我们创建了一个新的线程,并将 run 方法作为线程的执行逻辑。 除了基本的线程创建和启动,Java还提供了一些管理线程的方法和工具,例如: sleep 方法:使当前...
3.1 JAVA中的多线程与线程安全 6 3.1.1 Java中的多线程 6 3.1.2 Java中的线程安全 7 3.2 HTTP协议简介 8 3.3 断点续传原理 8 4 需求分析 10 4.1用户需求分析 10 4.2 业务流分析 11 5. 整体设计 11 5.1 系统...
懒汉式—线程安全:加上synchronize之类保证线程安全的基础上的懒汉模式,相对性能很低,大部分时间并不需要同步 饿汉方式。指全局的单例实例在类装载时构建。 [2] 双检锁式。在懒汉式基础上利用synchronize关键字和...
Java多线程与线程安全实践-基于Http协议的断点续传.rar 是一个Java毕业设计项目,旨在探讨如何在Java中实现多线程下载和断点续传功能,同时确保线程安全。该项目的主要特点如下: 1. 多线程下载:项目采用了Java的...
> 创建对象时,加锁保证有且仅有一个 > (有线程安全问题) * `饿汉模式` > 不管用不用它,只要类被创建,这个实例就有 > 没有线程安全问题 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的...
线程的创建有继承Thread类和实现Runnable接口两种方式,通过Runnable方式可以更加容易实现多线程之间资源共享。 通过sleep可以使线程进入休眠状态,通过join方法可以让线程处于等待,其他线程执行完毕后继续执行。 ...
线程安全问题的产生是因为多个线程并发访问共享数据造成的,如果能将多个线程对共享数据的并发访问改为串行访问,即一个共享数据同一时刻只能被一个线程访问,就可以避免线程安全问题。锁正是基于这种思路实现的一种...
Interlocked 类提供了同步对多个线程共享的变量的访问的方法。如果该变量位于共享内存中,则不同进程的线程就可以使用该机制。互锁操作是原子的,即整个操作是不能由相 同变量上的另一个互锁操作所中断的单元。这在...
* 业务逻辑对事务和线程安全的要求 * 计算一下冲突的可能性 * 请多使用lock,少用Mutex Web和IIS * 应用程序池,WebApplication,和线程池之间有什么关系 * Web页面怎么调用异步WebService
做多媒体应用,经常需要在各线程间共享数据,本例子介绍了一...2. 线程安全,写入,读取块大小无限制。 3. 代码简单,一个类实现。提供详细测试例子。 注意: 测试例子只是为测试双线程读写。 N个线程,需要改写例子。
多线程基础介绍.........................................................................................................................................15 定义多线程术语...................................
不过一般的文档中给出的例子往往只是“例子”,要用于实际的项目开发中差的很远,共享一下我以前写的一个线程安全的生产者消费者队列类。具有如下特点: 1.可以设置队列中的最大长度; 2.线程安全; 3.多线程想向...
1 多线程基础介绍15 定义多线程术语15 符合多线程标准16 多线程的益处17 提高应用程序的响应 17 有效使用多处理器17 改进程序结构17 占用较少的系统资源17 结合线程和RPC(远程过程调用)18 多线程概念18 并发性和...