什么是Java的线程安全问题?

线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读/写完,其他线程才可使用。不会出现数据不一致或者数据污染。

线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据。

那么,理解下上面这段话,再抛出新的问题:

  • 什么是脏数据?
  • 什么情况会触发线程安全问题?为什么静态变量和线程安全结合紧密?
  • 如何解决线程安全问题?
  • 如何预防线程安全问题?

什么是脏数据?

先百度:脏数据

简单的说:

通俗的讲,当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是脏数据,依据脏数据所做的操作可能是不正确的。

直观的感觉有点像冲突。

什么情况会触发线程安全问题?为什么静态变量和线程安全结合紧密?

去网上找答案和分析,很多情况会看到这么一句话:

静态变量类型设置的不合理会造成线程不安全。

黑人问号。。。

我们来看下造成线程不安全的几个要素:

  • 多线程应用
  • 访问同一块/个数据;

多线程应用:一般来说基本上都是了;

访问同一块数据:这篇文章写的很好,转来分享:在多线程中使用静态方法是否有线程安全问题

总而言之就是这样子的:——》调用静态方法——》调用静态变量——》线程不安全

所以,直接引起线程不安全的是不安全的静态变量,前面并不重要;

如何解决线程安全问题?

对症下药:

  • 不安全的变量——》安全的变量;
  • 静态——》动态(每次使用时生成)

后一个方法可以说是设计或者业务上的问题了,需要注意的是第一个,也就是哪些是线程安全,哪些线程不安全,还经常被用作静态变量。

这里举两个碰到的例子:

  • SimpleDateFormat,不安全;
  • StringBuilder,不安全,StringBuffer,安全;

另外,也可以对大量代码进行同步操作,但不是很推荐:

1、同步方法

给多线程访问的成员方法加上synchronized修饰符

public void synchronized doWork(){
// TODO
}

使用synchronized修饰的方法,就叫做同步方法,保证线程执行该方法的时候,其他线程只能在方法外等着。

2、同步代码块

synchronized(同步锁对象)
{
// 需要同步操作的代码
}

实际上,对象的同步锁只是一个概念,可以想象为在对象上标记了一个锁,谁拿到锁,谁就可以进入代码块,其他线程只能在代码块外面等着,而且注意,在任何时候,Java虚拟机最多允许一个线程拥有该同步锁。

Java程序运行可以使用任何对象作为同步监听对象,但是一般的,我们把当前并发访问的共同资源作为同步监听对象。

实际上,同步方法和同步代码块差不了多少,在本质上是一样的,两者都用了一个关键字synchronized,synchronized保证了多线程并发访问时的同步操作,避免线程的安全性问题,但是有一个弊端,就是使用synchronized的方法/代码块的性能比不用要低一些,因此如果要用synchronized,建议尽量减小synchronized的作用域。

如何预防线程安全问题?

其实这里想说的是是否需要在开发时对线程安全问题重点考虑。

为什么这么说呢?

比如StringBuilder和StringBuffer,在相应的API文档中有这样的描述:

将StringBuilder 的实例用于多个线程是不安全的。如果需要这样的同步,则建议使用StringBuffer。”,提到StringBuffer时,说到“StringBuffer是线程安全的可变字符序列,一个类似于String的字符串缓冲区,虽然在任意时间点上它都包含某种特定的字符序列,但通过某些方法调用可以改变该序列的长度和内容。可将字符串缓冲区安全地用于多个线程。可以在必要时对这些方法进行同步,因此任意特定实例上的所有操作就好像是以串行顺序发生的,该顺序与所涉及的每个线程进行的方法调用顺序一致”。StringBuilder是一个可变的字符序列,此类提供一个与StringBuffe兼容的API,但不保证同步。该类被设计用作StringBuffer的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比StringBuffer要快。将StringBuilder的实例用于多个线程是不安全的,如果需要这样的同步,则建议使用StringBuffer。

也就是说,一般推荐使用StringBuilder,这个不安全的家伙!!!

因为它快!!!

这里其实会有两个明显的疑问:

  • 快多少?
  • 会有静态的StringBuilder么?

快多少?看这个:String、StringBuffer、StringBuilder的区别与效率比较

结论是量级小看不出,量级大还是有区别。

会有静态的StringBuilder么?我没想到...

所以,线程安全并不是说开发中一直提心吊胆考虑的问题;

简单来说,有静态变量了,多思考下应用场景,查一下前辈踩过的坑,问题基本避免了。

至于衍生问题:为什么StringBuilder比StringBuffer快?源码告诉我们,后者有同步。

逐步理解Java中的线程安全问题的更多相关文章

  1. 浅谈利用同步机制解决Java中的线程安全问题

    我们知道大多数程序都不会是单线程程序,单线程程序的功能非常有限,我们假设一下所有的程序都是单线程程序,那么会带来怎样的结果呢?假如淘宝是单线程程序,一直都只能一个一个用户去访问,你要在网上买东西还得等 ...

  2. [译]线程生命周期-理解Java中的线程状态

    线程生命周期-理解Java中的线程状态 在多线程编程环境下,理解线程生命周期和线程状态非常重要. 在上一篇教程中,我们已经学习了如何创建java线程:实现Runnable接口或者成为Thread的子类 ...

  3. 深入理解Java中停止线程

    一.停止线程会带来什么? 对于单线程中,停止单线程就是直接使用关键字return或者break,但是在停止多线程时是让线程在完成任务前去开启另外一条线程,必须放弃当前任务,而这个过程是不可预测,所以必 ...

  4. Java中一个线程只有六个状态。至于阻塞、可运行、挂起状态都是人们为了便于理解,自己加上去的。

    java中,线程的状态使用一个枚举类型来描述的.这个枚举一共有6个值: NEW(新建).RUNNABLE(运行).BLOCKED(锁池).TIMED_WAITING(定时等待).WAITING(等待) ...

  5. Java中的线程池用过吧?来说说你是怎么理解线程池吧?

    前言 Java中的线程池用过吧?来说说你是怎么使用线程池的?这句话在面试过程中遇到过好几次了.我甚至这次标题都想写成[Java八股文之线程池],但是有点太俗套了.虽然,线程池是一个已经被说烂的知识点了 ...

  6. 深入理解Java中的不可变对象

    深入理解Java中的不可变对象 不可变对象想必大部分朋友都不陌生,大家在平时写代码的过程中100%会使用到不可变对象,比如最常见的String对象.包装器对象等,那么到底为何Java语言要这么设计,真 ...

  7. java中的线程安全

    在Java中,线程的安全实际上指的是内存的安全,这是由操作系统决定的. 目前主流的操作系统都是多任务的,即多个进程同时运行.为了保证安全,每个进程只能访问分配给自己的内存空间,而不能访问别的.分配给别 ...

  8. Java多线程编程(1)--Java中的线程

    一.程序.进程和线程   程序是一组指令的有序集合,也可以将其通俗地理解为若干行代码.它本身没有任何运行的含义,它只是一个静态的实体,它可能只是一个单纯的文本文件,也有可能是经过编译之后生成的可执行文 ...

  9. Java中的线程

    http://hi.baidu.com/ochzqvztdbabcir/item/ab9758f9cfab6a5ac9f337d4 相濡以沫 Java语法总结 - 线程 一 提到线程好像是件很麻烦很复 ...

随机推荐

  1. POJ 1979 Red and Black (BFS)

    链接 : Here! 思路 : 简单的搜索, 直接广搜就ok了. /****************************************************************** ...

  2. [luogu4159 SCOI2009] 迷路(矩阵乘法)

    传送门 Solution 矩阵乘法新姿势qwq 我们知道当边权为1是我们可以利用矩阵快速幂来方便的求出路径数 那么对于边权很小的时候,我们可以将每个点都拆成若干个点 然后就将边权不为1转化为边权为1了 ...

  3. 自定义UEditor右键菜单

    //打开右键菜单功能 ,enableContextMenu: true //右键菜单的内容,label留空支持国际化,否则以此配置为准 //,contextMenu:[ // { // label:' ...

  4. 继续聊WPF——自定义CheckBox控件外观

    上一篇文章中谈到了BulletDecorator控件,就是为自定义CheckBox控件的模板做准备,因为CheckBox需要比较严格的布局,正好,BulletDecorator控件就合适了,该控件的布 ...

  5. 一些诗词摘抄qwq

    声明: 有些违规内容就删掉了--大家都能理解吧qwq 雾失楼台,月迷津渡,桃源望断无寻处.可堪孤馆闭春寒,杜鹃声里斜阳暮.--秦观<踏莎行·郴州旅舍> 郴江幸自绕郴山,为谁流下潇湘去?-- ...

  6. Oracle关联查询-数据类型不一致问题 ORA-01722: 无效数字

    一.存在表A和表B,都包含字段user_no,但数据类型不一致,如下: create table A ( user_id varchar2(20), user_no number(12,0), xxx ...

  7. Number Puzzle

    Number Puzzle Time Limit: 2 Seconds      Memory Limit: 65536 KB Given a list of integers (A1, A2, .. ...

  8. 【bzoj1025】【SCOI2009】【游戏】【dp】

    Description windy学会了一种游戏.对于1到N这N个数字,都有唯一且不同的1到N的数字与之相应.最開始windy把数字按顺序1,2.3.--,N写一排在纸上. 然后再在这一排以下写上它们 ...

  9. unity游戏开发之NGUI的UISprite染色

    游戏的UI开发中常常会遇到染色问题.比如button失效变灰的效果,同一个道具通过策划表配的颜色值染上红绿蓝紫等颜色,效果例如以下 最笨最挫的方法当然是让美术多出几个资源图.这种一个缺点是浪费资源,在 ...

  10. pagex,screenx,clientx的差别

    screenX:參照物为电脑的屏幕左上角,距离电脑屏幕的水平距离 clientX:參照物是内容区域左上角,距离内容区域左上角的水平距离,会随着滚动栏的移动而移动 pageX:參照物也是内容区域的左上角 ...