线程安全的定义:当多个线程访问某个类时,不管运行环境采用何种调度方式或者这些线程如何交替执行,并且在主调用代码中不需要额外的同步和协调,这个类都能表现出正确的行为,那么这个类就是线程安全的。
线程安全性可能是非常复杂的,在没有充足同步的情况下,多个线程中的操作执行顺序是不可预测的,甚至会产生非常奇怪的结果。
如果当多个线程访问一个可变的共享变量时没有使用合适的同步,那么线程就会出现错误。有三种方式可以修复这个问题:
- 不在线程间共享变量
- 将可变的变量改为不可变的变量
- 在访问时使用同步。
有这样一个需求,需要按照序列顺序产生一个序列(不能有重复数据)
自增,看似是一个原子操作实际上一个自增包含三个操作步骤:获取变量值, 将变量值加1,将计算结果写入变量。
/** * * @author zhangwei_david * @version $Id: UnsafeSequence.java, v 0.1 2014年10月24日 下午9:38:54 zhangwei_david Exp $ */ public class UnsafeSequence { public static UnsafeSequence unsafeSequence = new UnsafeSequence(); public static UnsafeSequence getInstance() { return unsafeSequence; } private int value; public int getNext() { return value++; } }
这个类在单线程下是没有任何问题的,可以顺序的生成一个序列。
/** * * @author zhangwei_david * @version $Id: OneThread.java, v 0.1 2014年10月25日 下午9:50:32 zhangwei_david Exp $ */ public class OneThread { /** * * @param args */ public static void main(String[] args) { for (int i = 0; i < 100; i++) { System.out.println(UnsafeSequence.getInstance().getNext()); } } }
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
那么在多项线程下有是什么样的情况呢?
import java.util.concurrent.TimeUnit; /** * * @author zhangwei_david * @version $Id: Test.java, v 0.1 2014年10月24日 下午9:40:41 zhangwei_david Exp $ */ public class Test { /** * * @param args */ public static void main(String[] args) { for (int i = 0; i < 100; i++) { new Thread(new Runnable() { public void run() { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { } System.out.println(UnsafeSequence.getInstance().getNext()); } }).start(); } } } 0 15 18 17 21 24 28 16 14 2 0 1 13 12 5 10 31 33 37 11 6 8 9 7 41 43 40 39 38 36 34 35 45 49 58 32 30 29 27 26 25 23 22 4 20 3 19 88 87 86 85 83 84 80 82 81 79 78 77 76 89 90 74 75 73 72 71 70 94 95 69 67 68 66 65 64 63 97 62 61 59 60 57 56 55 54 53 52 51 50 48 47 46 44 42 98 96 93 92 91
我们可以发现在多线程下,打印的结果是乱序的。 是不是以此就可以断定这个类不是线程安全的内。当然不能,但因的结果是由线程调度和执行的时间决定的。 如果是线程安全的,最终的结果应该自增到99,可是最终没有自增到99,仔细查询结果可以发现有打印了连个零,也就是说有两个线程访问了同一个值,以此可以断定这个类不是线程安全的。
这是由于多线程要共享相同的内存地址空间,并且是并发运行,因此它们可能会访问或修改其他线程正在使用的变量。如果需要是共享的变量的行为可以预测就需要使用同步。如果没有使用同步,那么无论是编译器、硬件还是在运行时都可以对操作进行优化重新排序,这有助有提升性能但也为开发人员带来了负担。
那么如何将这个类改为线程安全的呢? 我们只需将获取下一个值的方法改为同步方法既可以解决这个问题。
/** * * @author zhangwei_david * @version $Id: Sequence.java, v 0.1 2014年10月24日 下午9:51:20 zhangwei_david Exp $ */ public class SafeSequence { private static class InstanceHolder { public static SafeSequence instance = new SafeSequence(); } public SafeSequence getInstance() { return InstanceHolder.instance; } private volatile int value = 0; public synchronized int getNext() { return value++; } }
相关推荐
servlet线程安全问题servlet线程安全问题
什么是线程安全? 答:线程安全是多线程编程时的计算机程序代码中的一个概念。在拥有共享数据的多条线程并行执行的程序中,线程安全的代码会通过同步机制保证各个线程都可以正常且正确的执行,不会出现数据污染等...
包括:Linux64位(非线程安全) swoole_loader56.so、swoole_loader70.so、swoole_loader71.so、swoole_loader72.so、swoole_loader73.so、swoole_loader74.so。 Linux64位(线程安全) swoole_loader56_zts.so、swoole_...
内容概要:文章内容从原子性、可见性、有序性三个方面介绍C++线程安全问题的原因。通过原子操作、线程同步如互斥锁、读写锁、条件变量、信号量等方法解决C++线程安全问题。同时介绍了线程安全的单例,饿汉模式和懒汉...
你还在用synchronized?线程安全相关知识深入剖析
C++线程安全日志库-Win32接口实现,博客讲解:https://www.cnblogs.com/swarmbees/ ->C++线程安全日志库-Win32接口实现
该文件中实例说明了如何在Labwindows/cvi中使用线程锁和线程安全变量进行多线程程序设计
众所周知,在普通的非线程安全队列有两种实现方式: 1.使用数组实现的循环队列。 2.使用链表实现的队列。 先看看两种方式的优劣: .Net Farmework中的普通队列Queue的实现使用了第一种方式,缺点是当队列空间不足会...
mysql是线程不安全的,mysql不是线程安全的,多线程共用同一个mysql连接是会崩溃的 QT的QSqlDatabase是基于mysql的,所以一样是线程不安全的 现讲明mysql为什么是线程不安全的,以及在多线程环境下如何使用mysql,...
c++ stl线程安全 c++ stl线程安全 c++ stl线程安全
servlet与Struts action线程安全问题分析
【C++ 语言】线程安全队列 ( 条件变量 | 线程调度 ) : https://hanshuliang.blog.csdn.net/article/details/102851323 下载完项目后 , 使用 Visual Studio 打开 , 注意需要配置 POSIX 线程库 ( 参考以下博客配置...
应用在多线程模式下 线程安全 写txt日志封装应用 调用示例
下面小编就为大家分享一篇浅谈C#跨线程调用窗体控件(比如TextBox)引发的线程安全问题,具有很好的参考价值,希望对大家有所帮助
原创手操,操作系统课设,线程安全的双向链表,VC6.0,无须配置,可运行
申明:不是原创,不是原创,只是转载。 这是一个来自网上的例子 ...用于测试QList的线程安全性,因原作者只给出源代码,没有给出测试结果,这里生成一个QT工程,打开即可编译,内部有ReadME.txt,简要说明
线程安全的单例模式 线程安全的单例模式 线程安全的单例模式
hiredis的c++封装, 线程安全, 提供对键值对、队列、散列、集合结构的读写