【JAVA多线程安全问题解析】

一、问题的提出

以买票系统为例:

 1 class Ticket implements Runnable
 2 {
 3     public int sum=10;
 4     public void run()
 5     {
 6         while(true)
 7         {
 8             if(sum>0)
 9             {
10                 System.out.println(Thread.currentThread().getName()+":"+sum--);
11             }
12         }
13     }
14 }
15 public class Demo
16 {
17     public static void main(String args[])
18     {
19         Ticket t=new Ticket();
20         new Thread(t).start();
21         new Thread(t).start();
22         new Thread(t).start();
23         new Thread(t).start();
24     }
25 }

这个代码有问题。仔细分析可以知道,如果四个线程同时进入了run方法中,假设当时sum==1,则第一个线程可以进入if块中,但是如果CPU突然切换到了其他线程,那么第一个线程将会等待CPU执行权,但是并没有改变sum的值,此时sum仍然是1;同理,假设极端情况发生了,即第2、3个线程均进入了if块,而且均在改变sum值之前就并指运行,等待CPU执行权,那么第四个线程改变完sum的值称为0之后,其余三个线程会将sum的值变为-1,-2,-3(但是输出只能到-2),很明显的,问题发生了,虽然几率不大,但是一旦发生就是致命的问题。

使用Thread.sleep()方法可以暂停线程的执行,通过输出即可检验。

 1 class Ticket implements Runnable
 2 {
 3     public int sum=10;
 4     public void run()
 5     {
 6         while(true)
 7         {
 8             if(sum>0)
 9             {
10                 try
11                 {
12                     Thread.sleep(50);
13                 }
14                 catch(InterruptedException e){}
15                 System.out.println(Thread.currentThread().getName()+":"+sum--);
16             }
17
18         }
19     }
20 }
21 public class Demo
22 {
23     public static void main(String args[])
24     {
25         Ticket t=new Ticket();
26         new Thread(t).start();
27         new Thread(t).start();
28         new Thread(t).start();
29         new Thread(t).start();
30     }
31 }

运行结果:

注意使用sleep方法产生的异常只能捕获不能抛出。

时间: 2024-08-25 17:00:44

【JAVA多线程安全问题解析】的相关文章

Java 多线程安全问题简单切入详细解析

线程安全 假如Java程序中有多个线程在同时运行,而这些线程可能会同时运行一部分的代码.如果说该Java程序每次运行的结果和单线程的运行结果是一样的,并且其他的变量值也都是和预期的结果是一样的,那么就可以说线程是安全的. 解析什么是线程安全:卖电影票案例 假如有一个电影院上映<葫芦娃大战奥特曼>,售票100张(1-100号),分三种情况卖票: 情况1 该电影院开设一个售票窗口,一个窗口卖一百张票,没有问题.就如同单线程程序不会出现安全问题一样. 情况2 该电影院开设n(n>1)个售票窗口

最全面的Java多线程用法解析

最全面的java多线程用法解析,如果你对Java的多线程机制并没有深入的研究,那么本文可以帮助你更透彻地理解Java多线程的原理以及使用方法. 1.创建线程 在Java中创建线程有两种方法:使用Thread类和使用Runnable接口.在使用Runnable接口时需要建立一个Thread实例.因此,无论是通过Thread类还是Runnable接口建立线程,都必须建立Thread类或它的子类的实例.Thread构造函数: public Thread( ); public Thread(Runnab

java基础知识回顾之java Thread类学习(五)--java多线程安全问题(锁)同步的前提

这里举个例子讲解,同步synchronized在什么地方加,以及同步的前提: * 1.必须要有两个以上的线程,才需要同步. * 2.必须是多个线程使用同一个锁. * 3.必须保证同步中只能有一个线程在运行,锁加在哪一块代码 那么我们要思考的地方有:1.知道我们写的哪些是多线程代码 2.明确共享数据 3.明确多线程运行的代码中哪些语句是操作共享数据的.. 4.要确保使用同一个锁. 下面的代码:需求:两个存户分别往银行存钱,每次村100块,分三次存完. class bank{ private int

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);//中断当前活跃的线程,或者

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

死锁:是两个或者两个以上的线程被无限的阻塞,线程之间互相等待所需资源. 线程死锁产生的条件: 当两个线程相互调用Join()方法. 当两个线程使用嵌套的同步代码块的时候,一个线程占用了另一个线程的锁,互相等待阻塞,就有可能产生死锁. 下面看代码: 代码1:死锁的案例 package com.lp.ecjtu.Thread; /* 死锁:常见情景之一:同步的嵌套. */ class Ticket implements Runnable { private int num = 100; Object

Java多线程-实例解析

Java多线程实例 3种实现方法Java中的多线程有三种实现方式:1.继承Thread类,重写run方法.Thread本质上也是一个实现了Runnable的实例,他代表一个线程的实例,并且启动线程的唯一方法就是通过Thread类的start方法.2.实现Runnable接口,并实现该接口的run()方法.创建一个Thread对象,用实现的Runnable接口的对象作为参数实例化Thread对象,调用此对象的start方法.3.实现Callable接口,重写call方法.Callable接口与Ru

java 多线程安全问题-同步代码块

/* 多线程的安全问题: while(true) { if(tick>0) { //线程0,1,2,3在余票为1时,都停滞在这里,之后分别获得CPU执行权,打印出0,-1,-2等错票 System.out.println(Thread.currentThread().getName()+"....sale : "+ tick--); } } 问题的原因: 当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行一部分,还没有执行完,停滞 另一个线程参与进来执行,导致共享数据

java多线程安全问题-同步修饰符于函数

上一篇文章通过卖票使用同步代码块的方法解决安全问题本篇文章首先探讨如何找出这样的安全问题,并提出第二种方式(非静态函数synchronized修饰)解决安全问题 /* 需求: 银行有一个公共账号金库 有两个储户同时对该账户存取,每次存100,共3次 目的: 该程序是否有安全问题,如果有,如何解决 思路:如何找问题? 1,明确哪些代码是多线程运行代码 2,明确共享数据 3,明确多线程运行代码中哪些语句是操作共享数据的 */ /* 该程序中Bank是一个资源(私有属性和公有方法),Runnable接

java多线程安全问题 静态函数的修饰

/* 如果同步函数被静态修饰后,使用的锁是什么呢? 通过验证,发现不在是this.因为静态方法中也不可以定义this. 静态进内存是,内存中没有本类对象,但是一定有该类对应的字节码文件对象. 类名.class 该对象的类型是Class 静态的同步方法,使用的锁是该方法所在类的字节码文件对象. 类名.class */ class Ticket implements Runnable { private static int tick = 100; //Object obj = new Object