先看一个售票案例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. linux学习第四天 (Linux就该这么学)2018年11月16日

    今天主要讲了 管道符,重写向与环境变量 输入输出重写向 标准输出重写向 (标准,覆盖,错误) > 将标准输出重写向到一个文件中 >> 追加到文件 2>错误输出重定向 2> ...

  2. MySQL中的联结表

    使用联结能够实现用一条SELECT语句检索出存储在多个表中的数据.联结是一种机制,用来在一条SELECT语句中关联表,不是物理实体,其在实际的数据库表中并不存在,DBMS会根据需要建立联结,且会在查询 ...

  3. Spring ApplicationContext(十)finishRefresh

    ApplicationContext(十)finishRefresh Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) 经过 ...

  4. nginx指令中的优化(配置文件)

    nginx指令中的优化(配置文件)worker_processes 8; nginx进程数,建议按照cpu数目来指定,一般为它的倍数.worker_cpu_affinity 00000001 0000 ...

  5. swift NSdata 转换 nsstring

    result = NSString(data: data, encoding: NSUTF8StringEncoding) 做HTTP 请求时 遇到 打印结果看  所以~~~

  6. 690. Employee Importance

    好几种写法,这里贴几个出来 第一种:暴力解法,除去递归栈,空间复杂度O(1).时间复杂度略高 /* // Employee info class Employee { public: // It's ...

  7. 1.The Necessity of a Broad Education 全面教育的必要性

    1.The Necessity of a Broad Education 全面教育的必要性 (1) According to a survey,which was based on the respo ...

  8. shell 脚本学习

    Shell简介 概述 Shell是一种具备特殊功能的程序,它提供了用户与内核进行交互操作的一种接口.它接收用户输入的命令,并把它送入内核去执行.内核是Linux系统的心脏,从开机自检就驻留在计算机的内 ...

  9. vue2.0路由-路由嵌套

    vue一个重要的方面就是路由,下面是自己写的一个路由的例子: 1.引入依赖库就不必再说 2.创建组件 两种写法 第一种:间接 <template id="home"> ...

  10. SpringMVC处理模型数据

    目录结构 web.xml <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi= ...