线程安全问题:简单来说,就是在多线程的调度下,导致出现了一些随机性,随机性使代码出现 了一些bug =>线程不安全

造成线程不安全的原因有哪些呢?

1)抢占式执行,调度过程随机(也是万恶之源,无法解决)

2)多个线程同时修改同一个变量(可以适当调整代码结构,避免这种情况)

3)针对变量的操作,不是原子的(加锁,synchronized)

4)内存可见性,一个线程频繁读,一个线程写(使用volatile)

5)指令重排序(使用synchronized)

解决方法:

1)使用synchronized关键字以及synchronized的基本使用

synchronized的本质操作,是修改了Object对象中的“对象头”里面的一个标记,只有当两个线程同时针对一个对象加锁,才会产生竞争

把synchronized加到普通的方法上,也就相当于把锁对象指定为this了

把synchronized加到代码块上,就需要手动锁定,锁对象是啥(针对那个对象加锁)

把synchronized加到静态方法上,所谓的“静态方法”更严谨的叫法,应该叫做“类方法”,普通的方法,更严谨的叫法,叫做”实例方法“ ,针对类对象加锁如下:

类对象就是运行程序的时候,.class文件被加载到JVM内存中的模样

2)synchronized的特性

1.互斥
synchronized 会起到互斥效果, 某个线程执行到某个对象的 synchronized 中时, 其他线程如果也执行到
同一个对象 synchronized 就会阻塞等待.
进入 synchronized 修饰的代码块, 相当于 加锁
退出 synchronized 修饰的代码块, 相当于 解锁

2.刷新内存~synchronized 的工作过程
1. 获得互斥锁
2. 从主内存拷贝变量的最新副本到工作的内存
3. 执行代码
4. 将更改后的共享变量的值刷新到主内存
5. 释放互斥锁

3.可重入

可重入直观上来讲,就是同一个线程针对同一个锁,连续加锁了两次,如果出现了死锁,就是不可重入,如果不会死锁,就是可重入的~~

死锁:多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不可能正常终止

死锁的四个必要条件:

1)互斥使用~ 一个锁被一个线程占用了之后,其他线程占用不了(锁的本质,保证原子性)

2)不可抢占~ 一个锁被一个线程占用了之后,其他线程不能把这个锁给抢走

3)请求与保持~ 当一个线程占据了多把锁之后,除非显式的释放锁,否则这些锁是始终都是被该线程所持有的

4)环路等待,等待关系(为避免环路等待,只需要约定好,针对多把锁加锁的时候,有固定的顺序即可)

2)volatile关键字

volatile保证内存可见性,禁止编译器优化

volatile只是处理一个线程读,一个线程写的情况

volatile不保证原子性,也不会引起线程阻塞

3)wait和notify

由于线程之间是抢占式执行的,因此线程之间执行的顺序难以预知,因此我们需要合理的协调多个线程之间的执行先后顺序

完成这个协调工作, 主要涉及到三个方法
wait() / wait(long timeout): 让当前线程进入等待状态.
notify() / notifyAll(): 唤醒在当前对象上等待的线程.
注意: wait, notify, notifyAll 都是 Object 类的方法.

1,wait()方法

wait 做的事情:

public static void main(String[] args) throws InterruptedException {
Object object = new Object();
synchronized (object) {
System.out.println("等待中");
object.wait();
System.out.println("等待结束");
}
}

1.使当前执行代码的线程进行等待. (把线程放到等待队列中)

2.释放当前的锁

3.满足一定条件时被唤醒,重新尝试获取这个锁
注意:wait 要搭配 synchronized 来使用. 脱离 synchronized 使用 wait 会直接抛出异常.

wait 结束等待的条件:

1.其他线程调用该对象的 notify 方法.

2.wait 等待时间超时 (wait 方法提供一个带有 timeout 参数的版本, 来指定等待时间).

3.其他线程调用该等待线程的 interrupted 方法, 导致 wait 抛出 InterruptedException 异常

2,notify()方法:

notify 方法是唤醒等待的线程.

static class WaitTask implements Runnable {
private Object locker;
public WaitTask(Object locker) {
this.locker = locker;
}
@Override
public void run() {
synchronized (locker) {
while (true) {
try {
System.out.println("wait 开始");
locker.wait();
System.out.println("wait 结束");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
static class NotifyTask implements Runnable {
private Object locker;
public NotifyTask(Object locker) {
this.locker = locker;
}
@Override
public void run() {
synchronized (locker) {
System.out.println("notify 开始");
locker.notify();
System.out.println("notify 结束");
}
}
}
public static void main(String[] args) throws InterruptedException {
Object locker = new Object();
Thread t1 = new Thread(new WaitTask(locker));
Thread t2 = new Thread(new NotifyTask(locker));
t1.start();
Thread.sleep(1000);
t2.start();
}

1.方法notify()也要在同步方法或同步块中调用,该方法是用来通知那些可能等待该对象的对象锁的
其它线程,对其发出通知notify,并使它们重新获取该对象的对象锁。

2.如果有多个线程等待,则有线程调度器随机挑选出一个呈 wait 状态的线程。(并没有 "先来后到")

3.在notify()方法后,当前线程不会马上释放该对象锁,要等到执行notify()方法的线程将程序执行
完,也就是退出同步代码块之后才会释放对象锁。

notifyAll()方法

notify方法只是唤醒某一个等待线程. 使用notifyAll方法可以一次唤醒所有的等待线程

wait和sleep的对比(简单了解即可)

wait用于线程之间的通信的,sleep是让线程阻塞一段时间

唯一的相同点就是都可以让线程放弃执行一段时间.

1. wait 需要搭配 synchronized 使用. sleep 不需要.

2. wait 是 Object 的方法 sleep 是 Thread 的静态方法

线程安全问题的原因及解决方案相关推荐

  1. 线程安全问题的原因和解决方案

    一.首先产生线程安全的原因: (一)站在开发者的角度看:①多个线程之间操作同一个数据②至少有一个线程修改这个数据(不是读操作而是写操作) (二)站在系统的角度看:一条语句对应多个指令,线程调度可以发生 ...

  2. 线程安全问题的 3 种解决方案!

    作者 | 磊哥 来源 | Java面试真题解析(ID:aimianshi666) 转载请联系授权(微信ID:GG_Stone) 线程安全是指某个方法或某段代码,在多线程中能够正确的执行,不会出现数据不 ...

  3. 线程安全问题及其解决方案

    一:线程安全问题的原因: 1.线程是抢占式执行的,即具有随机性 2.多线程的情况下,线程同时去修改同一个数据或者有的线程在修改数据,有的线程在读取数据 3.一条语句对应多个指令,这些指令操作并不是原子 ...

  4. 多个线程直接按对数据进行操作容易引发线程安全问题

    参考链接:http://www.cnblogs.com/paddix/p/5374810.html 代码: public class Count {public int num;public void ...

  5. 使用同步机制解决线程安全问题

    线程的生命周期: 什么情况会产生线程安全问题? 当多个线程同时共享同一个全局变量或静态变量,做写的操作时,可能会发生数据冲突问题,即产生线程安全问题.读的操作不会发生线程安全问题. 例子:上文中的卖票 ...

  6. 多线程中的线程安全问题

    多线程中的线程安全问题 概述: ​ 多条线程在操作同一个资源的时候发生的数据交叉问题就是线程安全问题 产生原因: ​ 多条线程操作同一个资源 解决思路: ​ 要线程排队解决安全问题,设定权限. 如何设 ...

  7. Java多线程基础-6:线程安全问题及解决措施,synchronized关键字与volatile关键字

    线程安全问题是多线程编程中最典型的一类问题之一.如果多线程环境下代码运行的结果是符合我们预期的,即该结果正是在单线程环境中应该出现的结果,则说这个程序是线程安全的. 通俗来说,线程不安全指的就是某一代 ...

  8. java 全局变量线程安全_Java线程安全问题指的是全局变量,还是静态变量?

    这个问题的答案是静态变量和全局变量都可能引起线程安全问题.这两种变量引起线程安全问题的原因和区别如下: 1.静态变量 静态变量即静态成员变量.只要有修改变量值的操作,无论是在单例或者非单例都是线程不安 ...

  9. iOS多线程全套:线程生命周期,多线程的四种解决方案,线程安全问题,GCD的使用,NSOperation的使用(上)

    2017-07-08 remember17 Cocoa开发者社区 目的 本文主要是分享iOS多线程的相关内容,为了更系统的讲解,将分为以下7个方面来展开描述. 多线程的基本概念 线程的状态与生命周期 ...

最新文章

  1. i5 10400f相当于几代i7_十代酷睿i9/i7/i5差异惊人!功耗/温度放飞自我
  2. C语言的双向链表头插法和尾插法,指定节点删除
  3. javascript-数据类型,json与数组,获取非行间样式
  4. Hibernate【XXXX.hbm.xml】总结
  5. Panda和numpy库和matplotlib库的安装
  6. [css] box-sizing的宽度包含了哪些?
  7. Android与server通信的方法之中的一个(json)效率不高安全性不好
  8. 2017-2018-20172309 《程序设计与数据结构》第五周学习总结
  9. 火影忍者 动漫 全集目录 分章节 精彩打斗剧集 思维导图整理
  10. java十进制_JAVA 十进制 转换成 三进制
  11. vue+element自动计算天数
  12. 【C语言进阶】C语言程序设计:动态通讯录(顺序表实现)
  13. golang-如何用全局参数打印程序运行信息
  14. SketchUp: Modeling Exteriors from Photos SketchUp:从照片建模外部 Lynda课程中文字幕
  15. 在计算机中 汉字系统把一个汉字表示为,计算机问题汉字系统在计算机内把一个汉字表示 – 手机爱问...
  16. 顶会论文笔记:联邦学习——ATPFL: Automatic Trajectory Prediction Model Design under Federated Learning Framework
  17. 【Android】小白进阶之回调监听机制listener
  18. Oracle-SQL查询表的一条数据
  19. javascript中使用枚举定义一个对象进行数据转换
  20. 概率统计:数学期望、方差、协方差、相关系数、矩

热门文章

  1. element-ui中tree连动
  2. 【Android组件开发】自定义的多宫格布局
  3. 【Spring Data JPA】基于 JpaRepository 增删改查
  4. arcmap叠置分析_8.4. 叠置分析
  5. ubuntu根目录扩容
  6. Designing an optimal contest(博弈论+机制设计) 论文阅读笔记
  7. pyqt5写代码流程
  8. C语言计算两日期间隔天数
  9. 数据库(增删改查、mysql建课程表)
  10. Python import 功能(进阶篇)