一、线程安全问题

如果有多个线程在同时运行,而这些线程可能会同时运行这段代码。程序每次运行结果和单线程运行的结果是一样 的,而且其他的变量的值也和预期的是一样的,就是线程安全的。

简单来说就是多线程访问了共享数据,就会产生线程安全问题

举例如下:

举个例子,比如电影院卖某电影票100张,三个窗口同时卖

模拟票:

public class Ticket implements Runnable {
private int ticket = 100;
/*
* 执行卖票操作
*/
@Override
public void run() {
//每个窗口卖票的操作
//窗口 永远开启
while (true) {
if (ticket > 0) {//有票 可以卖
//出票操作
//使用sleep模拟一下出票时间
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto‐generated catch block
e.printStackTrace();
}
//获取当前线程对象的名字
String name = Thread.currentThread().getName();
System.out.println(name + "正在卖:" + ticket‐‐);
}
}
}
}

测试类:

public class Demo {
public static void main(String[] args) {
//创建线程任务对象
Ticket ticket = new Ticket();
//创建三个窗口对象
Thread t1 = new Thread(ticket, "窗口1");
Thread t2 = new Thread(ticket, "窗口2");
Thread t3 = new Thread(ticket, "窗口3");
//同时卖票
t1.start();
t2.start();
t3.start();
}
}

发现程序出现了两个问题: 1. 相同的票数,比如5这张票被卖了两回。 2. 不存在的票,比如0票与-1票,是不存在的。 这种问题,几个窗口(线程)票数不同步了,这种问题称为线程不安全。

线程安全问题都是由全局变量及静态变量引起的。若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步, 否则的话就可能影响线程安全。

产生线程安全问题的原因:

二、线程同步

线程同步用于解决线程安全问题

有三种方式完成同步操作:1. 同步代码块。 2. 同步方法。 3. 锁机制。

【1】同步代码块

同步代码块: synchronized 关键字可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。

格式:

把共享数据的代码放在代码块里

同步锁:对象的同步锁只是一个概念,可以想象为在对象上标记了一个锁.

1. 锁对象 可以是任意类型。 2. 多个线程对象 要使用同一把锁。

注意:在任何时候,最多允许一个线程拥有同步锁,谁拿到锁就进入代码块,其他的线程只能在外等着 (BLOCKED)。

注意:1.通过代码块中的锁对象,可以使用任意的对象

2.但是必须保证多个线程使用的锁对象是同一个

3.锁对象的作用:把同步代码块锁住,只让一个线程在同步代码块执行

同步技术的原理:

public class Ticket implements Runnable{
private int ticket = 100;
Object lock = new Object();
/*
* 执行卖票操作
*/
@Override
public void run() {
//每个窗口卖票的操作
//窗口 永远开启
while(true){
synchronized (lock) {
if(ticket>0){//有票 可以卖
//出票操作
//使用sleep模拟一下出票时间
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto‐generated catch block
e.printStackTrace();
}
//获取当前线程对象的名字
String name = Thread.currentThread().getName();
System.out.println(name+"正在卖:"+ticket‐‐);
}
}
}
}
}

【2】同步方法

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

使用步骤:1.把访问了共享数据的代码抽取出来,放到一个方法里去

2.把方法添加上synchronized修饰符

public class Ticket implements Runnable{
private int ticket = 100;
/*
* 执行卖票操作
*/
@Override
public void run() {
//每个窗口卖票的操作
//窗口 永远开启
while(true){
sellTicket();
}
}
/*
* 锁对象 是 谁调用这个方法 就是谁
* 隐含 锁对象 就是 this
*
*/
public synchronized void sellTicket(){
if(ticket>0){//有票 可以卖
//出票操作
//使用sleep模拟一下出票时间
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto‐generated catch block
e.printStackTrace();
}
//获取当前线程对象的名字
String name = Thread.currentThread().getName();
System.out.println(name+"正在卖:"+ticket‐‐);
}
}
}

2.同步锁是谁? 对于非static方法,同步锁就是this,锁对象是谁?谁调用这个方法就是谁,就是this。在这个程序里就是Runable的实现类对象

3.对于static方法,要访问的变量也要是静态的,

静态方法的锁对象是谁?静态的会在创建对象之前就进入内存,锁对象是本类的class属性,class文件对象

【3】Lock锁

Lock锁接口中有俩个方法:public void lock() :加同步锁。 public void unlock() :释放同步锁。

Lock接口有个实现类ReentrantLock

使用步骤:1.在成员位置创建一个ReentrantLock对象

2.在可能出现安全问题的代码前调用Lock接口中的方法lock获取锁

3.在可能出现安全问题的代码后调用Lock接口中的方法unlock获取锁

public class Ticket implements Runnable{
private int ticket = 100;
Lock lock = new ReentrantLock();
/*
* 执行卖票操作
*/
@Override
public void run() {
//每个窗口卖票的操作
//窗口 永远开启
while(true){
lock.lock();
if(ticket>0){//有票 可以卖
//出票操作
//使用sleep模拟一下出票时间
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto‐generated catch block
e.printStackTrace();
}
//获取当前线程对象的名字
String name = Thread.currentThread().getName();
System.out.println(name+"正在卖:"+ticket‐‐);
}
lock.unlock();
}
}
}

线程安全,线程同步,解决线程同步问题相关推荐

  1. 什么是线程安全问题 及怎么解决线程安全问题

    1.什么是线程安全问题 就是 多线程环境中 , 且存在数据共享 , 一个线程访问的共享 数据被其他线程修改了, 那么就发生了线程安全问题 , 整个访问过程中 , 无一共享的数据被其他线程修改了 就是线 ...

  2. Java多线程(4)--线程的同步解决线程安全问题

    多线程出现安全问题 问题的原因: 当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行,导致共享数据的错误. 解决办法: 对多条操作共享数据的语 ...

  3. 02java进阶03-异常、线程、同步、线程池、Lambda表达式、File类、递归

    目录 一.异常 二.异常的处理 三.自定义异常 四.多线程 五.线程.同步 5.1.线程 5.2同步 5.3线程安全 5.4线程状态 六.等待唤醒机制 6.1 线程间通信 6.2 等待唤醒机制 6.3 ...

  4. Java解决线程安全问题

    文章目录 背景 1. 线程安全问题 1.1 什么是线程安全? 1.2 产生的原因 1.3 实例(买票超卖问题) 1.4 如何确定是否存在线程安全问题? 2. 如何解决线程安全问题? 2.1 不可变(I ...

  5. int linux 原子操作_linux c++编程之多线程:原子操作如何解决线程冲突

    在多线程中操作全局变量一般都会引起线程冲突,为了解决线程冲突,引入原子操作. 1.线程冲突 #include #include #include #include int g_count = 0;vo ...

  6. Python多任务(3.线程--多线程共享全局变量,利用同步解决资源竞争,利用互斥锁)

    1. 线程之间是共享全局变量的 验证代码: import threading import time# 定义一个全局变量 g_num = 100def test1(): # 修改g_num的值glob ...

  7. 同步代码块解决线程安全

    案例:需求现在有100张火车票,有两个窗口同时抢火车票,请使用多线程模拟抢票效果. 代码: package com.learn;class ThreadDemo01 implements Runnab ...

  8. java 多线程跑数据_java——多线程的实现方式、三种办法解决线程赛跑、多线程数据同步(synchronized)、死锁...

    多线程的实现方式:demo1.demo2 demo1:继承Thread类,重写run()方法 packagethread_test;public class ThreadDemo1 extendsTh ...

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

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

最新文章

  1. sql 集合查询 数据更新操作语句
  2. 创建线性表,以及表中的基本操作
  3. 在线文档预览方案-office web apps
  4. awk - 模式扫描与处理语言
  5. 穿越栅栏 Overfencing
  6. Linux中mysql的卸载和重装,在Linux下面卸载与重新安装Postgresql
  7. C# 中是否支持 Like 和 ln 条件的参数化查询 ?
  8. Zookeeper面试题锦集
  9. 使用Memory DC
  10. 爬取知乎回答点赞数_python3 爬虫 之只需要问题id爬取知乎问题全部回答
  11. ubuntu学习日记--Lesson6:shell,bash,dash
  12. Debian中proftpd+mysql+虚拟用户+匿名用户+磁盘限额的配置
  13. TFS 2017 持续集成速记
  14. fmea第五版pfmea表格_第五版PFMEA模板(含附属评分准则编写指南全套EXCEL表)
  15. laravel 框架命令
  16. Java实现名字按拼音排序和多条件排序
  17. Linux与Windows设置共享文件夹的实现
  18. 霍尔 磁电 光电式测数传感器的优缺点比较
  19. AdxMenu真的不错!我写了个中文的使用说明如下,希望大家用得着
  20. java饲养员喂动物案例,封装、继承、多态、接口

热门文章

  1. linux 安装apache apu,Apache编译安装
  2. Python AIML搭建聊天机器人(附遇到的问题及解决)
  3. 对于波特率传输一个bit的时间的计算
  4. matlab实现nc文件批量转tif文件
  5. 【CS231n assignment 2022】Assignment 3 - Part 3,Transformer
  6. EOS智能合约开发系列(一)
  7. Java引用包的方法
  8. BookKeeper存储设计浅析
  9. 在安卓手机上安装Linux子系统
  10. 3种伺服电机控制方式