Java学习:线程的安全问题
线程的安全问题
模拟卖票案例
创建三个的线程,同时开启,对共享的票进行出售
public class RunnableImpl implementsc Runnable{
//定义一个多线程共享的票源
private int ticket = 100; //设置线程任务:买票
@Override
public void run(){
//使用死循环,让卖票操作重复执行
while (true){
//先判断票是否存在
if(ticket>0){
//提高安全问题出现的概率,让程序睡眠
try{
Thread.sleep(10);
}catch (InterruptedException e){
e.printStackTrace();
}
//票存在,卖票 ticket--
System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket+"张票");
ticket --;
}
}
}
} public class CaiNiao{
public static void main(String[] args){
//创建Runnable接口的实现类对象
RunnableImpl run = new RunnableImpl();
//创建Thread类对象,构造方法中传递Runnable接口的实现类对象
Thread t0 = new Thread(run);
Thread t1 = new Thread(run);
Thread t2 = new Thread(run);
//调用start方法开启多线程
t0.start();
t1.start();
t2.start();
}
}
这样会导致一个结果
- Thread-0 -->正在卖第1张票
- Thread-1 -->正在卖第1张票
- Thread-2 -->正在卖第0张票
解决线程安全问题的一种方案:使用同步代码块
格式:
格式:
syncharonized(锁对象){
可能会出现线程安全问题的代码(访问了共享数据的代码)
}
注意:
- 通过代码块中的锁对象,可以使用任意的对象
- 但是必须要保证多个线程使用的锁对象是同一个
锁对象作用
- 把同步代码块锁住,只让一个线程在同步代码中执行
public class RunnableImpl implementsc Runnable{
//定义一个多线程共享的票源
private int ticket = 100; //设置线程任务:买票
@Override
public void run(){
//使用死循环,让卖票操作重复执行
while (true){
//同步代码块
syncharonized(obj){
//先判断票是否存在
if(ticket>0){
//提高安全问题出现的概率,让程序睡眠
try{
Thread.sleep(10);
}catch (InterruptedException e){
e.printStackTrace();
}
//票存在,卖票 ticket--
System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket+"张票");
ticket --;
}
解决线程安全问题的二种方案:使用同步方法
使用步骤:
- 把访问了共享数据的代码抽取出来,放到一个方法中
- 在方法上添加synchronized修饰符
格式:定义方法的格式
修饰符 synchronized 返回值类型 方法名(参数列表){
可能会出现线程安全问题的代码(访问了共享数据的代码)
}
解决线程安全问题的三种方案:使用Lock锁
java.util.concurrent.Locks.Lock接口
Lock实现提供了比使用synchronized 方法和语句可获得的更广泛的锁定操作。
Lock接口中的方法:
void Lock()获取锁
void unLock() 释放锁
java.util.concurrent.Locks.ReentrantLock implements Lock 接口
使用步骤:
- 在成员位置创建一个ReentrantLock对象
- 在可能会出现安全问题的代码前调用Lock接口中的方法Lock获取锁
- 在可能会出现安全问题的代码前调后用Lock接口中的方法unLock释放锁
//1.在成员位置创建一个ReentrantLock对象
Lock l = new ReentrantLock(); @Override
public void run(){
//使用死循环,让卖票操作重复执行
while (true){
//2. 在可能会出现安全问题的代码前调用Lock接口中的方法Lock获取锁
l.lock(); //同步代码块
syncharonized(obj){
//先判断票是否存在
if(ticket>0){
//提高安全问题出现的概率,让程序睡眠
try{
Thread.sleep(10);
}catch (InterruptedException e){
e.printStackTrace();
}
//票存在,卖票 ticket--
System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket+"张票");
ticket --;
}
//3.在可能会出现安全问题的代码前调后用Lock接口中的方法unLock释放锁
l.unLock();//无论程序释放异常,锁都会释放
Java学习:线程的安全问题的更多相关文章
- 【转】Java学习---线程间的通信
[原文]https://www.toutiao.com/i6572378564534993415/ 两个线程间的通信 这是我们之前的线程. 执行效果:谁抢到资源,谁运行~ 实现线程交替执行: 这里主要 ...
- Java学习之多线程(线程安全问题及线程同步)
一.线程安全问题产生前提:1.多线程操作共享数据2.线程任务中有多条代码 class Ticket implements Runnable { //2.共享数据 private int num = 1 ...
- Java多线程--线程安全问题的相关研究
在刚刚学线程的时候我们经常会碰到这么一个问题:模拟火车站售票窗口售票.代码如下: package cn.blogs.com.isole; /* 模拟火车站售票窗口售票,假设有50张余票 */ publ ...
- Java学习笔记-多线程-创建线程的方式
创建线程 创建线程的方式: 继承java.lang.Thread 实现java.lang.Runnable接口 所有的线程对象都是Thead及其子类的实例 每个线程完成一定的任务,其实就是一段顺序执行 ...
- Java核心知识点学习----线程中如何创建锁和使用锁 Lock,设计一个缓存系统
理论知识很枯燥,但这些都是基本功,学完可能会忘,但等用的时候,会发觉之前的学习是非常有意义的,学习线程就是这样子的. 1.如何创建锁? Lock lock = new ReentrantLock(); ...
- Java基础-线程安全问题汇总
Java基础-线程安全问题汇总 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.内存泄漏和内存溢出(out of memory)的区别 1>.什么是内存溢出 答:内存溢出指 ...
- Java基础-线程操作共享数据的安全问题
Java基础-线程操作共享数据的安全问题 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.引发线程安全问题 如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运 ...
- java学习笔记15--多线程编程基础2
本文地址:http://www.cnblogs.com/archimedes/p/java-study-note15.html,转载请注明源地址. 线程的生命周期 1.线程的生命周期 线程从产生到消亡 ...
- java学习笔记14--多线程编程基础1
本文地址:http://www.cnblogs.com/archimedes/p/java-study-note14.html,转载请注明源地址. 多线程编程基础 多进程 一个独立程序的每一次运行称为 ...
随机推荐
- PHP 多图上传,图片批量上传插件,webuploader.js,百度文件上传插件
PHP 多图上传,图片批量上传插件,webuploader.js,百度文件上传插件(案例教程) WebUploader作用:http://fex.baidu.com/webuploader/gett ...
- 【JavaScript】案例三:使用JS完成页面定时弹出广告——事件(onload)
事件(onload) *注意点: 变量加var局部变量,不加var全局变量 setInterval() 方法会不停地调用函数,直到 clearInterval() 被调用或窗口被关闭. 返回值:返回 ...
- Bootstrap基础学习 ---- 系列文章
[Bootstrap基础学习]05 Bootstrap学习总结 [Bootstrap基础学习]04 Bootstrap的HTML和CSS编码规范 [Bootstrap基础学习]03 Bootstrap ...
- Jmeter做webservices接口测试
在Soap/XML-RPC Data中输入: <?xml version="1.0" encoding="utf-8"?> <soap12:E ...
- React / Ant Design Pro 实现Canvas画布实时自适应
如何实现canvas根据父容器进行自适应? Ant Design的组件都提供了强大的自适应能力,为了对齐父组件,镶嵌在Ant Design组件里的canvas也需要能根据父级容器进行自适应的能力,页面 ...
- Pandas | 14 统计函数
统计方法有助于理解和分析数据的行为.可以将这些统计函数应用到Pandas的对象上. pct_change()函数 系列,DatFrames和Panel都有pct_change()函数.此函数将每个元素 ...
- [RN] React Native 获取验证码 按钮
React Native 获取验证码 按钮 效果如图: 实现方法: 一.获取验证码 按钮组件 封装 CountDownButton.js "use strict"; import ...
- 什么是ES5?js中的'use strict'是什么?目的是什么?
什么是ES5? ECMA Script5:ECMA(欧洲计算机制造联合会)的第五次改版,2009年. js中的'use strict'是什么? js的严格模式 目的: ①添加更多报错的场合,消除代码的 ...
- 使用emplace操作
C++ 11新标准中引入了三个新成员——emplace_front.emplace和emplace_back,这些操作构造而不是拷贝元素.这些操作分别对应push_front.insert和push_ ...
- servlet中的doGet()与doPost()以及service()的用法
doget和dopost的区别 get和post是http协议的两种方法,另外还有head, delete等 1.这两种方法有本质的区别,get只有一个流,参数附加在url后,大小个数有严格限制且只能 ...