java基础知识回顾之java Thread类学习(四)--java多线程安全问题(锁)
上一节售票系统中我们发现,打印出了错票,0,-1,出现了多线程安全问题。我们分析为什么会发生多线程安全问题?
看下面线程的主要代码:
@Override
public void run() {
// TODO Auto-generated method stub while(true){
if(ticket > 0){//当线程0被调起的时候,当执行到这条判断语句的时候,线程1被调起抢了CPU资源,线程0进入冻结状态。
try {
Thread.sleep(100);//中断当前活跃的线程,或者执行的线程
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在卖票"+ticket--);
//System.out.println(Thread.currentThread().getId());
//System.out.println(Thread.currentThread().getName());
} }
}
分析:当100张票卖到剩余最后1张的时候,也就是ticket=1的时候,有三个线程Thread-0,Thread-1,Thread-2,这时候,Thread-0进入if(ticket > 0)这个条件具备了执行资格,但不具备执行权。正在这个时候,CPU切换到了Thread-1,Thread-1也进入了if(ticket > 0)这个条件下面,CPU又切换到了Thread-2,Thread-2又进入阻塞状态。这个时候三个线程都通过了if(ticket > 0)判断,都要往下执行了,这个时候CPU的资源被Thread-0第一个线程抢到,执行ticket=1,ticket--,那么第一个线程执行完打印出ticket=1,CPU被Thread-2抢到,打印出ticket=0,同理线程3执行完打印出ticket=-1,这就出现了线程安全的问题。
通过上面的分析大家知道了多线程安全产生的原因:当多条语句(if(ticket>0)和ticket--)在操作同一个线程的共享数据的时候(这里共享数据为ticket=100),一个线程执行了多条语句的一部分,还没有执行完,另一个线程抢到CPU资源,执行。导致数据共享错误。那么怎么解决呢?
解决办法:当多条语句在操作共享数据时,只能让一个线程执行完,在执行的过程中,其它线程不可以参与执行。java对于多线程安全问题,提供了专业的解决方法,那就是锁。
synchronized(对象){
需要被同步的代码
}
这个“对象”被称为锁,持有锁的线程可以在同步代码块中执行,没有持有锁的线程即使获取到CPU的执行权,也进不去,因为没有获取锁。
* 火车上的卫生间-经典“
火车售票的问题的解决:代码如下:
public class TicketsRunnable implements Runnable {
private int ticket=100;
Object obj = new Object();//对象锁,共同步代码块使用
public TicketsRunnable(){
System.out.println("*****************************");
}
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
synchronized(obj){ //同步代码块
if(ticket > 0){//当线程0被调起的时候,当执行到这条判断语句的时候,线程1被调起抢了CPU资源,线程0进入冻结状态。
try {
Thread.sleep(100);//中断当前活跃的线程,或者执行的线程
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在卖票"+ticket--);
//System.out.println(Thread.currentThread().getId());
//System.out.println(Thread.currentThread().getName());
}
}
}
}
/**
* @param args
*/
public static void main(String[] args) {
TicketsRunnable runna = new TicketsRunnable();
Thread t1 = new Thread(runna);
Thread t2 = new Thread(runna);
Thread t3 = new Thread(runna);
t1.start();
t2.start();
t3.start();
}
}
通过测试,不会出现错票的问题。
分析代码:当火车票剩余1张的时候,这个时候假设Thread-0获取到了CPU的执行权,并且持有对象锁,进入if条件,打印出买票1。ticket--,这个时候即使其他的线程获取到CPU的执行资格,但是设Thread-0的锁还没有释放,其他的线程拿不到锁,这样就进入不了if条件,那么只要等Thread-0执行完,Thread-0执行完后,ticket=0,其他线程即使拿到锁,因为if(ticket > 0)不能进入,所以执行不了。整个程序结束,卖票终止。
总结:通过程序可以知道:同步的前提是:1.必须要有两个或者两个以上的线程,才需要同步。
2.必须是多个线程使用同一个锁。
3.要分析哪段代码需要加同步,必须保证同步中只能有一个线程在运行。
同步锁的好处与弊端:1.好处,解决了多线程操作同意资源安全性问题。
2.弊端:多个线程每次都需要判断锁,较为消耗资源
java基础知识回顾之java Thread类学习(四)--java多线程安全问题(锁)的更多相关文章
- java基础知识回顾之---java String final类普通方法
辞职了,最近一段时间在找工作,把在大二的时候学习java基础知识回顾下,拿出来跟大家分享,如果有问题,欢迎大家的指正. /* * 按照面向对象的思想对字符串进行功能分类. * ...
- Java基础知识回顾之七 ----- 总结篇
前言 在之前Java基础知识回顾中,我们回顾了基础数据类型.修饰符和String.三大特性.集合.多线程和IO.本篇文章则对之前学过的知识进行总结.除了简单的复习之外,还会增加一些相应的理解. 基础数 ...
- Java基础-进程与线程之Thread类详解
Java基础-进程与线程之Thread类详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.进程与线程的区别 简而言之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程 ...
- Java基础知识回顾(一):字符串小结
Java的基础知识回顾之字符串 一.引言 很多人喜欢在前面加入赘述,事实上去技术网站找相关的内容的一般都应当已经对相应知识有一定了解,因此我不再过多赘述字符串到底是什么东西,在官网中已经写得很明确了, ...
- java基础知识回顾之java Thread类学习(八)--java.util.concurrent.locks(JDK1.5)与synchronized异同讲解
看API文档介绍几个方法: JDK1.5中提供了多线程的升级解决方案: 特点: 1.将同步synchronized显示的替换成Lock 2.接口Conditio ...
- java基础知识回顾之java Thread类学习(三)--java线程实现常见的两种方式实现好处:
总结:实现Runnable接口比继承Thread类更有优势: 1.因为java只能单继承,实现Runnable接口可以避免单继承的局限性 2.继承Thread类,多个线程不能处理或者共享同一个资源,但 ...
- java基础知识回顾之java Thread类--java线程实现常见的两种方式实现Runnable接口(二)
创建线程的第二中方式: /** * 步骤: 1定义类实现Runnable接口 2.实现Runnable接口中的run方法. 3.通过Thread类建立线程对象,并将Run ...
- java基础知识回顾之javaIO类---FileWriter和FileReader
FileWriter类的构造方法定义如下: 1.public FileWriter(File file)throws IOException 字符流的操作比字节流操作好在一点,就是可以直接输出字符串了 ...
- java基础知识回顾之javaIO类--File类应用:过滤器接口FilenameFilter和FileFilter
FilenameFilter和FileFilter都是用来过滤文件,例如过滤,以.jpg或者.java结尾的文件,通过看他们的源码:通过使用File类中String[] list(FilenameFi ...
随机推荐
- C++模板实例化(1)
On-Demand实例化 当C++编译器遇到模板特化的时候,他会利用所给的实参替换对应的模板参数,从而产生该模板的特化.该过程是自动进行的.有时候也会被称为隐式实例化,或者是自动实例化. on-dem ...
- OSX 上初步尝试 asp.net 5
去年微软最令开源狗界振奋的消息就是 ASP.NET 的开放与开源这一消息了. 根据微软的介绍,与我之前的一些总结,可以看到 ASP.NET 以及 .NET 平台会有下面几个变化: 代码使用 Apach ...
- Linux下编译安装mysql-5.0.45.tar.gz
安装环境:VMware9(桥接模式) + Linux bogon 2.6.32-642.3.1.el6.x86_64(查看linux版本信息:uname -a) 先给出MySQL For Linux ...
- 《postfix MAIL服务搭建(第一篇):》RHEL6
初级篇:搭建发送端.接收端.邮件别名的添加从而达到邮件群发功能的实现. 我们都知道邮件服务器是2个服务端也就是说2个端口,一个是发送的端口,一个是收邮件的端口,我们平常所使用的发送,接收邮件的过程,只 ...
- 《CDN web加速代理》RHEL6
CDN加速代理环境的测试:192.168.1.这个网段是可以上网的,2网段不可以上网 一台apache服务器 :配置 只安装apche服务 IP 192.168.1.59 一台双网卡的服务器 :只安装 ...
- 处理jquery版本之间冲突
处理jquery版本之间冲突 前端开发们都知道jquery版本有好多,之间冲突很纠结.比如我刚来这公司的时候,后端的哥们用的是jQuery 1.3.2,我了个去,那哥们好久没更新了.我写的效果插件都是 ...
- css解决IE6、Chrome、ff 浏览器position:fixed;和闪动问题
首先说下开发模式,刚刚开始接触,基本沿用web端开发方式,目前开发模式上没有找到的适合的,现在基本这样:1,电脑nginx配置服务器3,电脑和手机连同一个局域网,2,android root 和 ip ...
- Golang container/ring闭环数据结构的使用方法
//引入包 import "container/ring" //创建闭环,这里创建10个元素的闭环 r := ring.New(10) //给闭环中的元素附值 for i := 1 ...
- Java注意的地方
oo: 单一原则(SRP) 开放封闭原则(OCP) 里氏替换原则(LSP) 依赖倒转原则(DIP) 接口分离原则(ISP) equals: 若两个对象equals为true,则他们的hashcode值 ...
- Hibernate 插入,修改,删除,查询语句
/* *具体操作hibernate的类 *增加,删除,修改,按ID查询,模糊查询,查询全部 **/ public class PersonOperate { //在hibernate中所有操作都是由S ...