Java线程同步-解决方法

Java多线程中存在线程同步问题。当线程a使用某一多线程共享的资源R时,线程b也使用资源R,就会出现问题。

先看一个例子:

本例设置3个售票窗口同时出售100张票,每个窗口出票间隔为1秒,直到卖完为止。

复制代码
 1 /*
 2  * 功能:制造线程同步问题
 3  */
 4 package com.miaoyu;
 5 
 6 public class Demo10 {
 7     public static void main(String[] args) {
 8         // TODO Auto-generated method stub
 9         TicketWindow tw1 = new TicketWindow();
10         
11         Thread t1 = new Thread(tw1);
12         Thread t2 = new Thread(tw1);
13         Thread t3 = new Thread(tw1);
14         t1.start();
15         t2.start();
16         t3.start();
17     }
18 
19 }
20 
21 class TicketWindow implements Runnable
22 {
23     private  int num = 100 ;
24     //间隔1s出票
25 
26     @Override
27     public void run() {
28         // TODO Auto-generated method stub
29         while(true)
30         {
31 
32             if(num>0)
33             {
34                 try {
35                     Thread.sleep(1000);
36                 } catch (InterruptedException e) {
37                     // TODO Auto-generated catch block
38                     e.printStackTrace();
39                 }
40                 System.out.println(Thread.currentThread().getName()+"正在售出第"+num+"张票");
41                 num--;
42             }else break;
43         }
44     }
45 }
复制代码

 

运行结果:

问题:

由运行结果可以看出,可能存在同一张票被多个窗口出售的情况。

原因:

 问题是由下边一段代码造成的。当线程1执行到System.out.println(Thread.currentThread().getName()+"正在售出第"+num+"张票");但还没有执行num--时,线程2也执行System.out.println,此时会输出同一个num。

复制代码
 1             if(num>0)
 2             {
 3                 try {
 4                     Thread.sleep(1000);
 5                 } catch (InterruptedException e) {
 6                     // TODO Auto-generated catch block
 7                     e.printStackTrace();
 8                 }
 9                 System.out.println(Thread.currentThread().getName()+"正在售出第"+num+"张票");
10                 num--;
11             }else
12             {
13                 break;
14             }
复制代码

 解决方法:

要保证线程原子性,即一个线程使用资源时,其他线程处于阻塞状态,排队等待。

使用对象锁就可以轻松解决。

1             synchronized (this) 
2             {
3                 (需要同步的代码段)
4             }

使用对象锁之后的程序:

复制代码
 1 /*
 2  * 功能:解决线程同步问题
 3  */
 4 package com.miaoyu;
 5 
 6 public class Demo10 {
 7     public static void main(String[] args) {
 8         // TODO Auto-generated method stub
 9         TicketWindow tw1 = new TicketWindow();
10         
11         Thread t1 = new Thread(tw1);
12         Thread t2 = new Thread(tw1);
13         Thread t3 = new Thread(tw1);
14         t1.start();
15         t2.start();
16         t3.start();
17     }
18 
19 }
20 
21 class TicketWindow implements Runnable
22 {
23     //定义剩余票数num
24     private  int num = 100 ;
26 
27     @Override
28     public void run() {
29         // TODO Auto-generated method stub
30         while(true)
31         {
32             //保证原子性,【同步代码块】
33             synchronized (this) 
34             {
35                 if(num>0)
36                 {
37                     try {
38                         //出票间隔随机
39                         Thread.sleep((int)(Math.random()*2000));
40                     } catch (InterruptedException e) {
41                         // TODO Auto-generated catch block
42                         e.printStackTrace();
43                     }
44                     System.out.println(Thread.currentThread().getName()+"正在售出第"+num+"张票");
45                     num--;
46                 }else break;
47             }
48         }
49     }
50 }
复制代码

运行结果:

 

对Java同步机制的解释:

 Java任意类型的对象都有一个标志位,该标志位具有0,1两种状态,其开始状态为1,当某个线程执行了synchronized(object)语句后,object对象的标志位变为0状态,直到执行完整个synchronized语句中的代码块后,该对象的标志位又回到1状态。

当一个线程执行到synchronized(object)语句的时候,先检查object对象的标志位,如果为0状态,表明已经有另外的线程正在执行synchronized包括的代码,那么这个线程将暂时阻塞,让出cpu资源,直到另外的线程执行完相关的同步代码,并将object对象的标志位变为1状态,这个线程等阻塞就取消,线程能继续运行,该线程又将object的标志位变为0状态,防止其他的线程再进入相关的同步代码块中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值