先看一个售票案例Demo,多线程程序对共享数据操作引发的安全问题:

package android.java.thread09;

/**
* 售票线程
*/
class Booking implements Runnable { /**
* 模拟票的总算 10张票
*/
private int ticket = 10; @Override
public void run() { while (true) { if (ticket > 0) {
// 让线程在这里停一下,会更加容易复现线程的安全问题,就算不加这行代码,安全问题依然有
try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("名称:" + Thread.currentThread().getName() + "窗口卖出第" + ticket + "张票");
ticket--;
} } }
} /**
* 售票案例
*/
public class BookingTest { public static void main(String[] args) { /**
* 定义Runnable实现类Booking,此实现类Booking不是线程,此实现类Booking给四个Thread去执行的
*/
Runnable booking = new Booking(); // 实例化线程对象
Thread thread1 = new Thread(booking); // 此实现类Booking给Thread去执行的
Thread thread2 = new Thread(booking); // 此实现类Booking给Thread去执行的
Thread thread3 = new Thread(booking); // 此实现类Booking给Thread去执行的
Thread thread4 = new Thread(booking); // 此实现类Booking给Thread去执行的 // 开启启动线程
thread1.start(); // 启动第Thread-0窗口 执行卖票任务
thread2.start(); // 启动第Thread-1窗口 执行卖票任务
thread3.start(); // 启动第Thread-2窗口 执行卖票任务
thread4.start(); // 启动第Thread-3窗口 执行卖票任务 } }

打印的日志结果,注意:⚠️ 没有打印的日志结果都不同,这是CPU对线程非常快速的切换造成的,哪个线程先有执行权 就执行哪个线程 都是随机的

名称:Thread-0窗口卖出第10张票
名称:Thread-3窗口卖出第9张票
名称:Thread-1窗口卖出第8张票
名称:Thread-2窗口卖出第7张票
名称:Thread-0窗口卖出第6张票
名称:Thread-3窗口卖出第5张票
名称:Thread-2窗口卖出第4张票
名称:Thread-1窗口卖出第4张票
名称:Thread-2窗口卖出第2张票
名称:Thread-0窗口卖出第1张票
名称:Thread-3窗口卖出第1张票
名称:Thread-1窗口卖出第-1张票
名称:Thread-2窗口卖出第-2张票

CPU的随机性,到底切换到哪个线程,到底执行哪个线程代码的多少行,等等,都是随机的

 

分析原因,为什么会出现以上日志打印的各个情况呢,为什么会出现 0张票 -1张票   这种情况呢?,看以下CPU执行线程的随机性就明白了


通过以上画图分析原因,造成安全问题的有以下两个因素:

  1.线程任务中,发现有共享数据,例如:ticket。

  2.多线程操作共享数据,例如:ticket。

造成的原因是:Thread-0在对共享数据操作过程中,CPU执行了Thread-1对共享数据操作,   相当于:我在数钱,突然我出去有事了,然后有个人拿了500块钱,等我在回来数钱的时候,就已经发生是数据安全问题


解决多线程安全问题,synchronize 加同步代码块,同步代码块:synchronize{ 操作共享数据的代码 }

package android.java.thread09;

/**
* 售票线程
*/
class Booking implements Runnable { /**
* 模拟票的总算 10张票
*/
private int ticket = 10; @Override
public void run() { while (true) { /**
* 加入了同步代码块的代码synchronized,
* 不管CPU如何疯狂的切换执行,
* 只要同步代码块里面的代码没有执行完,
* 就不准其他线程进来执行
* 这样就保证了多线程操作共享数据的安全新
*/
synchronized (Booking.class) { // 同步操作共享数据的代码 if (ticket > 0) { // 让线程在这里停一下,会更加容易复现线程的安全问题,就算不加这行代码,安全问题依然有
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
} System.out.println("名称:" + Thread.currentThread().getName() + "窗口卖出第" + ticket + "张票");
ticket--;
}
} } }
} /**
* 售票案例
*/
public class BookingTest { public static void main(String[] args) { /**
* 定义Runnable实现类Booking,此实现类Booking不是线程,此实现类Booking给四个Thread去执行的
*/
Runnable booking = new Booking(); // 实例化线程对象
Thread thread1 = new Thread(booking); // 此实现类Booking给Thread去执行的
Thread thread2 = new Thread(booking); // 此实现类Booking给Thread去执行的
Thread thread3 = new Thread(booking); // 此实现类Booking给Thread去执行的
Thread thread4 = new Thread(booking); // 此实现类Booking给Thread去执行的 // 开启启动线程
thread1.start(); // 启动第Thread-0窗口 执行卖票任务
thread2.start(); // 启动第Thread-1窗口 执行卖票任务
thread3.start(); // 启动第Thread-2窗口 执行卖票任务
thread4.start(); // 启动第Thread-3窗口 执行卖票任务 } }

以下日志结果,是CPU随机执行到哪个线程,就哪个线程打印,CPU执行线程的随机性很重要

以下日志结果,是CPU随机执行到哪个线程,就哪个线程打印,CPU执行线程的随机性很重要

以下日志结果,是CPU随机执行到哪个线程,就哪个线程打印,CPU执行线程的随机性很重要

.........

Android-多线程安全问题-synchronized的更多相关文章

  1. java多线程以及Android多线程

    Java 多线程 线程和进程的区别 线程和进程的本质:由CPU进行调度的并发式执行任务,多个任务被快速轮换执行,使得宏观上具有多个线程或者进程同时执行的效果. 进程:在操作系统来说,一个运行的程序或者 ...

  2. Android多线程分析之四:MessageQueue的实现

    Android多线程分析之四:MessageQueue的实现 罗朝辉 (http://www.cnblogs.com/kesalin/) CC 许可,转载请注明出处 在前面两篇文章<Androi ...

  3. Android多线程分析之三:Handler,Looper的实现

    Android多线程分析之三:Handler,Looper的实现 罗朝辉 (http://www.cnblogs.com/kesalin/) CC 许可,转载请注明出处 在前文<Android多 ...

  4. Android多线程分析之二:Thread的实现

    Android多线程分析之二:Thread的实现 罗朝辉 (http://www.cnblogs.com/kesalin/) CC 许可,转载请注明出处   在前文<Android多线程分析之一 ...

  5. 无废话Android之smartimageview使用、android多线程下载、显式意图激活另外一个activity,检查网络是否可用定位到网络的位置、隐式意图激活另外一个activity、隐式意图的配置,自定义隐式意图、在不同activity之间数据传递(5)

    1.smartimageview使用 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android&q ...

  6. java基础知识回顾之java Thread类学习(四)--java多线程安全问题(锁)

    上一节售票系统中我们发现,打印出了错票,0,-1,出现了多线程安全问题.我们分析为什么会发生多线程安全问题? 看下面线程的主要代码: @Override public void run() { // ...

  7. android 多线程断点续传下载

    今天跟大家一起分享下Android开发中比较难的一个环节,可能很多人看到这个标题就会感觉头很大,的确如果没有良好的编码能力和逻辑思维,这块是很难搞明白的,前面2次总结中已经为大家分享过有关技术的一些基 ...

  8. Android多线程及异步处理问题

    1.问题提出 1)为何需要多线程? 2)多线程如何实现? 3)多线程机制的核心是啥? 4)到底有多少种实现方式? 2.问题分析 1)究其为啥需要多线程的本质就是异步处理,直观一点说就是不要让用户感觉到 ...

  9. 多线程安全问题之Lock显示锁

    package com.hls.juc; import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.Reentr ...

随机推荐

  1. MySQL学习笔记-MySQL数据库优化实践[转]

    最近一段时间,我们整理了一些关于Percona,Linux,Flashcache,硬件设备的优化经验,分享给大家: 硬件 1.开启BBWC RAID卡都有写cache(Battery Backed W ...

  2. eclipse中tomcat调试正确关联源码

    1.build path中jar包关联本地源码 2.tomcat中添加source关联工程lib下的jar包 以上两步即可. 可解决tomcat直接关联本地源码debug时无法计算表达式的情况. 错误 ...

  3. JDK8集合类源码解析 - ArrayList

    ArrayList主要要注意以下几点: 1构造方法 2添加add(E e) 3 获取 get(int index) 4 删除 remove(int index)    ,   remove(Objec ...

  4. android windows的一些item属性

    <item name="android:windowFrame">@null</item> :Dialog的windowFrame框为无 <item ...

  5. jquery动态出操作select

    var citys = {1:'北京',2:'上海',3:'广州',4:'深圳'}; $("#city option:gt(0)").remove(); for(var k in ...

  6. [C#.Net]C#连接Oracle数据库的方法

    首先介绍下开发环境:WIn10 64bit+Visual Studio 2015+Oracle10ClientWin32(只是客户端,如果安装整个数据库也是可以的) 目前了解C#中连接Oracle数据 ...

  7. js网页上画图

    保存 1.d3.js  (http://www.d3.org/)使用svg技术,展示大数据量,动态效果很好,但是API暴露的不好,得靠自己摸索. 2.http://raphaeljs.com/refe ...

  8. MyBatis 实现新增

    MyBatis实现新增 1.概念学习:(角度不同) 1.1 功能:从应用程序角度出发,软件具有哪些功能 1.2 业务:完成功能时的逻辑,对应Service中一个方法 1.3 事务:从数据库角度出发,完 ...

  9. php中如何配置项目虚拟路径

    php虚拟目录的设置在apache目录下打开conf->httpd.conf文件,找到<IfModule dir_module>,在</IfModule>后面添加如下代码 ...

  10. yyparse() and yylex()

    Yacc 与 Lex 快速入门 yyparse() returns a value of 0 if the input it parses is valid according to the give ...