关于多线程安全的解决方案
2012-05-10 10:07
169 查看
在spring中默认的service是singleton的,这就造成了一个问题:在有共享变量(比如static变量,有时候我们不得不这么做)的时候,需要考虑到该共享变量的多线程安全问题。
解决这个问题有几个方法:
1.借助支持多线程安全的对象创建方式。如果是static Map类型的变量,在不需要考虑并发的情况下我们可以这么创建
private static Map<T1,T2> MY_MAP = new HashMap<T1,T2>();
但是HashMap是非线程安全的,大家可能会想到HashTable,HashTable使用synchonized方法实现,会造成很大的性能问题。在JDK1.5及以后的版本中新增了一个包 java.util.concurrent,这个包中的方法既能控制并发又不影响性能,这个时候应该这样创建该Map对象:
private static Map<T1,T2> MY_MAP = new ConcurrentHashMap<T1,T2>();
这样就从变量级别的进行了并发控制,性能几乎不受什么影响。
2.除此之外我们还可以借助synchonized来进行线程同步,使得并发时线程锁定资源排队获取资源,这样能保证共享变量的多线程安全.具体实现方法如下:
private static Object MY_LOCK = new Object();
可以锁定一个方法 :
public synchonized(MY_LOCK) Map<T1,T2> getMyMap(){
...
}
但是如果你只是为了保护几个共享变量的话,没必要整个类同步,只要针对共享变量的操作进行同步即可
private static Map<T1,T2> MY_MAP = new HashMap<T1,T2>();
public Map<T1,T2> getMyMap(){
synchonized(MY_LOCK){
MY_MAP = appService.getMyMap();
}
...
}
3.类似于synchonized,java.utils.concurrent包下lock类也可以作为对象锁来使用,之前要导入java.utils.concurrent.locks.ReentrantLock类文件
private ReentrantLock myLock = new ReentrantLock();
public Map<T1,T2> getMyMap(){
myLock.lock();
try{
MY_MAP = appService.getMyMap();
}finally{
myLock.unlock();
}
...
}
这里需要注意的是,将需要锁住的模块放在 myLock.lock() 和myLock.unlock()语句之间,为了方便锁的释放,通常都将锁放在try{}最后一定要释放锁。
4.synchronized 和Lock的异同。主要相同点:Lock能完成Synchronized所实现的所有功能。主要不同点:Lock有比synchronied更精确的线程语义和更好的性能。Synchronized会自动释放所,而Lock一定要程序员手工释放,一般都在finally子句中释放。
java安全结束多线程的方式
回归正题,当我们查看JDK API的时候,总会发现一些类说明写着,线程安全或者线程不安全,比如说StringBuilder中,有这么一句,"将StringBuilder
的实例用于多个线程是不安全的。如果需要这样的同步,则建议使用StringBuffer. ",那么下面手动创建一个线程不安全的类,然后在多线程中使用这个类,看看有什么效果。
Count.java:
public class Count {
private int num;
public void count() {
for(int i = 1; i <= 10; i++) {
num += i;
}
System.out.println(Thread.currentThread()。getName() + "-" + num);
}
}
在这个类中的count方法是计算1一直加到10的和,并输出当前线程名和总和,我们期望的是每个线程都会输出55.
ThreadTest.java:
public class ThreadTest {
public static void main(String[] args) {
Runnable runnable = new Runnable() {
Count count = new Count();
public void run() {
count.count();
}
};
for(int i = 0; i < 10; i++) {
new Thread(runnable)。start();
}
}
}
这里启动了10个线程,看一下输出结果:
Thread-0-55
Thread-1-110
Thread-2-165
Thread-4-220
Thread-5-275
Thread-6-330
Thread-3-385
Thread-7-440
Thread-8-495
Thread-9-550
只有Thread-0线程输出的结果是我们期望的,而输出的是每次都累加的,这里累加的原因以后的博文会说明,那么要想得到我们期望的结果,有几种解决方案:
1. 将Count中num变成count方法的局部变量;
public class Count {
public void count() {
int num = 0;
for(int i = 1; i <= 10; i++) {
num += i;
}
System.out.println(Thread.currentThread()。getName() + "-" + num);
}
}
2. 将线程类成员变量拿到run方法中;
public class ThreadTest4 {
public static void main(String[] args) {
Runnable runnable = new Runnable() {
public void run() {
Count count = new Count();
count.count();
}
};
for(int i = 0; i < 10; i++) {
new Thread(runnable)。start();
}
}
}
3. 每次启动一个线程使用不同的线程类,不推荐。
上述测试,我们发现,存在成员变量的类用于多线程时是不安全的,而变量定义在方法内是线程安全的。想想在使用struts1时,不推荐创建成员变量,因为action是单例的,如果创建了成员变量,就会存在线程不安全的隐患,而struts2是每一次请求都会创建一个action,就不用考虑线程安全的问题。
解决这个问题有几个方法:
1.借助支持多线程安全的对象创建方式。如果是static Map类型的变量,在不需要考虑并发的情况下我们可以这么创建
private static Map<T1,T2> MY_MAP = new HashMap<T1,T2>();
但是HashMap是非线程安全的,大家可能会想到HashTable,HashTable使用synchonized方法实现,会造成很大的性能问题。在JDK1.5及以后的版本中新增了一个包 java.util.concurrent,这个包中的方法既能控制并发又不影响性能,这个时候应该这样创建该Map对象:
private static Map<T1,T2> MY_MAP = new ConcurrentHashMap<T1,T2>();
这样就从变量级别的进行了并发控制,性能几乎不受什么影响。
2.除此之外我们还可以借助synchonized来进行线程同步,使得并发时线程锁定资源排队获取资源,这样能保证共享变量的多线程安全.具体实现方法如下:
private static Object MY_LOCK = new Object();
可以锁定一个方法 :
public synchonized(MY_LOCK) Map<T1,T2> getMyMap(){
...
}
但是如果你只是为了保护几个共享变量的话,没必要整个类同步,只要针对共享变量的操作进行同步即可
private static Map<T1,T2> MY_MAP = new HashMap<T1,T2>();
public Map<T1,T2> getMyMap(){
synchonized(MY_LOCK){
MY_MAP = appService.getMyMap();
}
...
}
3.类似于synchonized,java.utils.concurrent包下lock类也可以作为对象锁来使用,之前要导入java.utils.concurrent.locks.ReentrantLock类文件
private ReentrantLock myLock = new ReentrantLock();
public Map<T1,T2> getMyMap(){
myLock.lock();
try{
MY_MAP = appService.getMyMap();
}finally{
myLock.unlock();
}
...
}
这里需要注意的是,将需要锁住的模块放在 myLock.lock() 和myLock.unlock()语句之间,为了方便锁的释放,通常都将锁放在try{}最后一定要释放锁。
4.synchronized 和Lock的异同。主要相同点:Lock能完成Synchronized所实现的所有功能。主要不同点:Lock有比synchronied更精确的线程语义和更好的性能。Synchronized会自动释放所,而Lock一定要程序员手工释放,一般都在finally子句中释放。
java安全结束多线程的方式
(1)用interrupt() ;中断线程就可以了
(2)run(){ while(flag = true){ ...... } }将flag设为flase即可
Java线程:线程安全与不安全
作为一个Java web开发人员,很少也不需要去处理线程,因为服务器已经帮我们处理好了。记得大一刚学Java的时候,老师带着我们做了一个局域网聊天室,用到了AWT、Socket、多线程、I/O,编写的客户端和服务器,当时做出来很兴奋,回学校给同学们演示,感觉自己好NB,呵呵,扯远了。上次在百度开发者大会上看到一个提示语,自己写的代码,6个月不看也是别人的代码,自己学的知识也同样如此,学完的知识如果不使用或者不常常回顾,那么还不是自己的知识。大学零零散散搞了不到四年的Java,我相信很多人都跟我一样,JavaSE基础没打牢,就急忙忙、兴冲冲的搞JavaEE了,然后学习一下前台开发(html、css、javascript),有可能还搞搞jquery、extjs,再然后是Struts、hibernate、spring,然后听说找工作得会linux、oracle,又去学,在这个过程中,是否迷失了,虽然学习面很广,但就像《神雕侠侣》中黄药师评价杨过,博而不精、杂而不纯,这一串下来,感觉做Java开发好难,并不是学着难,而是知识面太广了,又要精通这个,又要精通那个,这只是我迷茫时候的想法,现在我已经找到方向了。回归正题,当我们查看JDK API的时候,总会发现一些类说明写着,线程安全或者线程不安全,比如说StringBuilder中,有这么一句,"将StringBuilder
的实例用于多个线程是不安全的。如果需要这样的同步,则建议使用StringBuffer. ",那么下面手动创建一个线程不安全的类,然后在多线程中使用这个类,看看有什么效果。
Count.java:
public class Count {
private int num;
public void count() {
for(int i = 1; i <= 10; i++) {
num += i;
}
System.out.println(Thread.currentThread()。getName() + "-" + num);
}
}
在这个类中的count方法是计算1一直加到10的和,并输出当前线程名和总和,我们期望的是每个线程都会输出55.
ThreadTest.java:
public class ThreadTest {
public static void main(String[] args) {
Runnable runnable = new Runnable() {
Count count = new Count();
public void run() {
count.count();
}
};
for(int i = 0; i < 10; i++) {
new Thread(runnable)。start();
}
}
}
这里启动了10个线程,看一下输出结果:
Thread-0-55
Thread-1-110
Thread-2-165
Thread-4-220
Thread-5-275
Thread-6-330
Thread-3-385
Thread-7-440
Thread-8-495
Thread-9-550
只有Thread-0线程输出的结果是我们期望的,而输出的是每次都累加的,这里累加的原因以后的博文会说明,那么要想得到我们期望的结果,有几种解决方案:
1. 将Count中num变成count方法的局部变量;
public class Count {
public void count() {
int num = 0;
for(int i = 1; i <= 10; i++) {
num += i;
}
System.out.println(Thread.currentThread()。getName() + "-" + num);
}
}
2. 将线程类成员变量拿到run方法中;
public class ThreadTest4 {
public static void main(String[] args) {
Runnable runnable = new Runnable() {
public void run() {
Count count = new Count();
count.count();
}
};
for(int i = 0; i < 10; i++) {
new Thread(runnable)。start();
}
}
}
3. 每次启动一个线程使用不同的线程类,不推荐。
上述测试,我们发现,存在成员变量的类用于多线程时是不安全的,而变量定义在方法内是线程安全的。想想在使用struts1时,不推荐创建成员变量,因为action是单例的,如果创建了成员变量,就会存在线程不安全的隐患,而struts2是每一次请求都会创建一个action,就不用考虑线程安全的问题。
相关文章推荐
- MySQL数据库中关于网络安全的解决方案
- 关于多线程安全的一些解决方法
- 4、关于HashMap在多线程下的不安全分析
- 黑马程序员-JDK1.5多线程安全解决方案Lock详解
- 关于公共安全解决方案的思考
- 黑马程序员——java中关于同步函数(或同步代码块)解决多线程安全问题的加锁
- Java多线程安全问题及解决方案
- 关于CoreData的多线程安全问题
- 黑马程序员 第五篇:关于多线程及其安全问题
- 关于CoreData和SQLite多线程访问时的线程安全问题
- 关于CoreData和SQLite多线程访问时的线程安全问题
- 【面试题】懒汉式的多线程安全问题解决方案
- 【互联网安全】关于移动APP漏洞风险,阿里送你解决方案
- 关于CoreData和SQLite多线程访问时的线程安全问题
- ArcGIS for Silverlight:关于尝试连接到REST端点时发生安全异常的解决方案
- 关于多线程环境下安全调用窗体控件方法
- 关于pageadmin配置过程中没有安全选项的问题解决方案
- 【原创】关于C#多线程安全问题的讨论
- 关于apk提交谷歌返回OpenSSL、libpng安全漏洞问题的解决方案
- JAVA多线程不安全问题解决方案(多线程并发同一资源)。