多线程安全问题。

线程安全问题主要出现在访问临界资源的时候,就是访问同一个对象的时候,可能会出现无法挽回的损失,特别是在关于资金安全方面的时候,当然还有数据库事务方面的问题。他们很类似,都是要保证数据的原子性。

那么在java中如何保证线程安全呢?

对与共同使用的对象进行加锁,意思是我使用的时候,那么你就必须等待,等我用完之后你再用,反之依然。就像上厕所,你去的时候我是不能去的。

如何加锁呢?下面写三个加锁的方式

首先看一下实例代码

 
 
  1. public class TraditionalSynchornizedTest {  
  2.  /**  
  3.   * @param args  
  4.   */ 
  5.  public static void main(String[] args) {  
  6.   new TraditonalSynchornizedTest().sartThread();  
  7.  }  
  8.  public void sartThread(){  
  9.   final Outerput outerput = new Outerput();  
  10.   new Thread(new Runnable(){  
  11.    @Override 
  12.    public void run() {  
  13.     while(true){  
  14.      try {  
  15.       Thread.sleep(5);  
  16.      } catch (InterruptedException e) {  
  17.       e.printStackTrace();  
  18.      }  
  19.      outerput.print("zhangsanfeng");  
  20.     }  
  21.    }  
  22.      
  23.   }).start();  
  24.   new Thread(new Runnable(){  
  25.    @Override 
  26.    public void run() {  
  27.     while(true){  
  28.      try {  
  29.       Thread.sleep(5);  
  30.      } catch (InterruptedException e) {  
  31.       e.printStackTrace();  
  32.      }  
  33.      outerput.print("luxiaofeng");  
  34.     }  
  35.    }  
  36.      
  37.   }).start();  
  38.  }  
  39.  public class Outerput{  
  40.   public void print(String name){  
  41.    for(int i = 0;i < name.length(); i++){  
  42.     System.out.print(name.charAt(i));  
  43.    }  
  44.    System.out.println();  
  45.   }  
  46.  }  

以上代码没有对共同持有的对象outerput加锁,所以会出现线程安全问题

1、对代码块加锁

对共同持有的对象加锁可以把内部类写成这样的

 
 
  1. public class Outerput{  
  2.   public void print(String name){  
  3.    synchronized (this) {  
  4.     for(int i = 0;i < name.length(); i++){  
  5.      System.out.print(name.charAt(i));  
  6.     }  
  7.     System.out.println();  
  8.    }  
  9.   }  
  10.  } 

2、对非静态方法加锁,加锁的对象是this

 
 
  1. public class Outerput{  
  2.   public synchronized void print(String name){  
  3.    for(int i = 0;i < name.length(); i++){  
  4.     System.out.print(name.charAt(i));  
  5.    }  
  6.    System.out.println();  
  7.   }  
  8.  }  

3、对静态方法加锁的对象到底是谁?

 
 
  1. public static synchronized  void print2(String name){  
  2.    for(int i = 0;i < name.length(); i++){  
  3.     System.out.print(name.charAt(i));  
  4.    }  
  5.    System.out.println();  
  6.   } 
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/*多线程_等待唤醒机制*/
 
/**
*需求:创建两个线程,一个进行存储信息,一个进行打印信息。
*目的:程序输入一个"mike man"打印一个"mike man"
*       输入一个"莉莉 女女女女女"打印一个"莉莉 女女女女女"
*步骤:创建一个共享资源类RescourceWaitNotifyDemo
*        创建输入线程类InputWaitNotifyDemo
*        创建打印线程类OutputWaitNotifyDemo
*        由主函数创建线程,并执行。
*问题:
*        为什么会有线程安全问题?
*        怎么解决?
*/
 
/*线程共享资源类,信息类*/
class ResourceWaitNotifyDemo //
{
     private String name;
     private String sex;
     private boolean flag=false;
 
 
     public synchronized void setInfo(String name,String sex)//信息输入函数
     {
         if(flag)
         /*如果flag值为false,则共享资源中没有信息,进行赋值
           如果为true,则共享资源中有信息没有打印,不进行赋值,进行wait操作
         */   
         {
             try
             {
                 this.wait();
             }
             catch (Exception e)
             {
             }
         }
         else
         {
             this.name = name;
             this.sex = sex;           
         }   
         flag=true;     //改变开关,让输入程序不能再次进行赋值,同时可以让打印程序启动
         this.notify();//唤醒输出线程
     }
 
     public synchronized void OutInfo()//信息输出函数
     {
         if (!flag)//如果flag值为ture,则共享资源中有信息,进行打印,否则等待
         {
             try
             {
                 this.wait();
             }
             catch (Exception e)
             {
             }
         }
         else
         {
             System.out.println(name+"......"+sex);           
         }       
         flag=false;    //改变开关,让输入程序可以进行赋值,同时让自己不能在打印
         this.notify();//唤醒输入线程
     }
}
 
/*输入线程*/
class InputWaitNotifyDemo implements Runnable
{
     private ResourceWaitNotifyDemo r;    //创建共享类引用
 
     InputWaitNotifyDemo(ResourceWaitNotifyDemo r)
     {
         this.r = r;    //接收共享类对象
     }
 
     public void run()
     {
         int x=0;
         while(true)
         {   
             if (x==0)
             {
                 r.setInfo("mike","man");
             }
             else
             {
                 r.setInfo("莉莉","女女女女女");
             }
             x=(x+1)%2;                       
         }
     }
 
}
 
/*输出线程*/
class OutputWaitNotifyDemo implements Runnable
{
     private ResourceWaitNotifyDemo r;
 
     OutputWaitNotifyDemo(ResourceWaitNotifyDemo r)
     {
         this.r = r;    //和输入线程操作同一个共享类对象
     }
 
     public void run()
     {
         while (true)
         {
             r.OutInfo();   
         }
     }
}
 
/*主函数*/
class ThreadWaitNotifyTest
{
     public static void main(String[] args)
     {
         ResourceWaitNotifyDemo res = new ResourceWaitNotifyDemo();
/*
         InputWaitNotifyDemo i = new InputWaitNotifyDemo(res);
         OutputWaitNotifyDemo o = new OutputWaitNotifyDemo(res);
 
         Thread t1 = new Thread(i);
         Thread t2 = new Thread(o);
 
         t1.start();
         t2.start();
*/
         new  Thread( new  InputWaitNotifyDemo(res)).start();     //创建输入线程
         new  Thread( new  OutputWaitNotifyDemo(res)).start();     //创建打印线程
     }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值