多线程中共享对象,创建线程安全类
编程技术  /  houtizong 发布于 3年前   59
当对象在多线程的环境下访问就会出现多种问题,所以我们的程序应该注意在多线环境下对象的状态安全访问以及修改。
线程限制
当对象的修改和访问都限制在单线程的环境下,就可以不用考虑类是否是线程安全了。而实现线程限制有两种方法:栈限制 和使用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的锁,让它自己保护它的状态,从而达到保护该对象状态的目的,所以在多线程范围内保护可变对象的状态,重要的是要清楚取得谁的锁才能真正地做到保护。
请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!
技术博客集 - 网站简介:
前后端技术:
后端基于Hyperf2.1框架开发,前端使用Bootstrap可视化布局系统生成
网站主要作用:
1.编程技术分享及讨论交流,内置聊天系统;
2.测试交流框架问题,比如:Hyperf、Laravel、TP、beego;
3.本站数据是基于大数据采集等爬虫技术为基础助力分享知识,如有侵权请发邮件到站长邮箱,站长会尽快处理;
4.站长邮箱:[email protected];
文章归档
文章标签
友情链接