Object中的同步机制[转]

Object中的同步机制

 
附件
robot.JPG(20.0 K)
 
切换到幻灯片模式

程序不是玩具,必须具备商业运作的稳定性。所以在运行的时候要充分考虑不同线程之间的同步性。在使用同步性技术的时候,考虑到标志布尔型变量与while循环搭配的效果容易对CPU造成很大的资源浪费,所以在这里采取了wait+notify技术。 
Java在设计之初就充分考虑到了线程同步的问题,因而在设计基础类Oject的时候就为其提供了基于同步技术的三个函数wait+notify+notifyAll。这就意味着你所编写的任何类都可以使用这些方法(虽然在某些时候这些方法是根本没有意义的)。 
我们知道,Thread对象的sleep()方法也可以使当前线程暂停运行。但sleep()方法和wait()方法从本质上来说是不一样的。sleep()使得一个进程进入睡眠状态,但其线程所占有的资源并没有释放。假设,你在synchronized模块(加函数锁或者对象锁)里调用了sleep(),虽然线程睡着了而且没有使用资源,但是它依然保存着锁,别的线程依然无法调用相关的synchronized模块。而wait()则不同,它实际上了是放弃了锁,将资源贡献出来,而使自己暂时离岗。这个离岗状态一直会持续到“boss”(其他的线程)调用了notify(),通知线程继续回来工作为止。 
关于线程同步的三个函数,JAVA DOC中是这样描述的: 
wait导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。当前的线程必须拥有此对象监视器。该线程发布对此监视器的所有权并等待,直到其他线程通过调用 notify 方法,或 notifyAll 方法通知在此对象的监视器上等待的线程醒来。然后该线程将等到重新获得对监视器的所有权后才能继续执行. 
notify唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。直到当前的线程放弃此对象上的锁定,才能继续执行被唤醒的线程。此方法只应由作为此对象监视器的所有者的线程来调用. 
"当前的线程必须拥有此对象监视器"与"此方法只应由作为此对象监视器的所有者的线程来调用"说明wait方法与notify方法必须在同步块内执行,即synchronized(obj之内). 
调用对像wait方法后,当前线程释放对像锁,进入等待状态.直到其他线程(也只能是其他线程)通过notify 方法,或 notifyAll.该线程重新获得对像锁. 
继续执行,记得线程必须重新获得对像锁才能继续执行.因为synchronized代码块内没有锁是寸步不能走的. 
下面我举一个实际例子来说明线程的同步问题: 
例子非常通俗易懂。我将构造一个机器人。该机器人有一个身子,两只胳膊和两条腿。除了身子不动外,头、腿和胳膊要有节律地运动。因为每个零件的运动都在单独的一个线程内,所以要想让胳膊和腿按照一定的顺序执行,必须使用同步机制。 
首先来看一个无规律运动的实例代码: 
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
package ql.abs;
 
import java.io.*;
import java.text.*;
import java.util.*;
import java.net.*;
import quanwen.*;    //常用函数
 
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
import javax.swing.border.*;
import java.util.Iterator;
import java.util.List;
 
/**
 * 一个未基于线程同步的小机器人
 */
public class ExpNoSync extends JFrame{
  JPanel pnlTop=new JPanel(),
         pnlBottom=new JPanel();
 
  JPanel pnlTopLeft=new JPanel(),
         pnlTopRight=new JPanel(),
         pnlTopCenter=new JPanel();
 
  JPanel armLeft=new Arm1(),
         pnlTopLeft2=new JPanel();
 
  JPanel armRight=new Arm2(),
         pnlTopRight2=new JPanel();
 
  JPanel pnlBottomLeft=new JPanel(),
         leg=new Leg(),
         pnlBottomRight=new JPanel();
 
  JPanel head=new Head();
 
  Container c;
 
 
  public ExpNoSync(){
    super("小机器人");
    armLeft.setPreferredSize(new Dimension(50,50));
    pnlTopLeft2.setPreferredSize(new Dimension(50,50));
 
    pnlTopCenter.setBackground(Color.white);
    pnlTopCenter.setPreferredSize(new Dimension(50,50));
    
 
    armRight.setPreferredSize(new Dimension(50,50));
    pnlTopRight2.setPreferredSize(new Dimension(50,50));
 
 
 
    pnlBottomLeft.setPreferredSize(new Dimension(50,50));
    leg.setPreferredSize(new Dimension(50,50));
    pnlBottomRight.setPreferredSize(new Dimension(50,50));
 
 
    c=getContentPane();
    c.setLayout(new GridLayout(3,3,0,0));
    c.add(pnlBottomLeft);
    c.add(head);
    c.add(pnlBottomRight);
    c.add(armLeft);
    c.add(pnlTopCenter);
    c.add(armRight);
    c.add(pnlTopRight2);
    c.add(leg);
    c.add(pnlTopRight);
 
    setSize(167,160);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    show(); 
  }
  public static void main(String[] args){
    ExpNoSync exp=new ExpNoSync();
  }
  class Arm1 extends JPanel{
     ImageIcon[] icon=new ImageIcon[2];
     int step=0;
     JLabel lblArm1=new JLabel();
     Runnable changeIt=new Runnable(){
       public void run(){
         lblArm1.setIcon(icon[step]);
       }
     };
     Thread t=new Thread(){
       public void run(){
         //休眠1秒钟
         while(true){
           try{
             this.sleep(500);
           }catch(Exception ex){return;}
 
           SwingUtilities.invokeLater(changeIt);              
 
           step++;
           if(step>1) step=0;
         }
       }
     };
     public Arm1(){
       icon[0]=new ImageIcon(Arm1.class.getResource("image/armLeft1.GIF"));
       icon[1]=new ImageIcon(Arm1.class.getResource("image/armLeft2.GIF"));
 
       setLayout(new FlowLayout(FlowLayout.RIGHT));
       lblArm1.setIcon(icon[step]);
       add(lblArm1);
       t.start();
     }
 
     public Dimension getPreferredSize(){
       return new Dimension(50,50);
     }
  }
  class Arm2 extends JPanel{
     ImageIcon[] icon=new ImageIcon[2];
     int step=0;
     JLabel lblArm2=new JLabel();
     Runnable changeIt=new Runnable(){
       public void run(){
         lblArm2.setIcon(icon[step]);
       }
     };
     Thread t=new Thread(){
       public void run(){
         //休眠1秒钟
         while(true){
           try{
             this.sleep(500);
           }catch(Exception ex){return;}
 
           SwingUtilities.invokeLater(changeIt);              
 
           step++;
           if(step>1) step=0;
         }
       }
     };
 
     public Arm2(){
       icon[0]=new ImageIcon(Arm2.class.getResource("image/armRight1.GIF"));
       icon[1]=new ImageIcon(Arm2.class.getResource("image/armRight2.GIF"));
 
       setLayout(new FlowLayout(FlowLayout.RIGHT));
       lblArm2.setIcon(icon[step]);
       add(lblArm2);
       t.start();
     }
     public Dimension getPreferredSize(){
       return new Dimension(50,50);
     }
  }
  class Leg extends JPanel{
     ImageIcon[] icon=new ImageIcon[2];
     int step=0;
     JLabel lblLeg=new JLabel();
     Runnable changeIt=new Runnable(){
       public void run(){
         lblLeg.setIcon(icon[step]);
       }
     };
     Thread t=new Thread(){
       public void run(){
         //休眠1秒钟
         while(true){
           try{
             this.sleep(500);
           }catch(Exception ex){return;}
 
           SwingUtilities.invokeLater(changeIt);              
 
           step++;
           if(step>1) step=0;
         }
       }
     };
 
     public Leg(){
       icon[0]=new ImageIcon(Leg.class.getResource("image/leg1.GIF"));
       icon[1]=new ImageIcon(Leg.class.getResource("image/leg2.GIF"));
 
       setLayout(new FlowLayout(FlowLayout.RIGHT));
       lblLeg.setIcon(icon[step]);
       add(lblLeg);
       t.start();
     }
     public Dimension getPreferredSize(){
       return new Dimension(50,50);
     }
  }
  class Head extends JPanel{
     ImageIcon[] icon=new ImageIcon[2];
     int step=0;
     JLabel lblHead=new JLabel();
     Runnable changeIt=new Runnable(){
       public void run(){
         lblHead.setIcon(icon[step]);
       }
     };
     Thread t=new Thread(){
       public void run(){
         //休眠1秒钟
         while(true){
           try{
             this.sleep(500);
           }catch(Exception ex){return;}
 
           SwingUtilities.invokeLater(changeIt);              
 
           step++;
           if(step>1) step=0;
         }
       }
     };
 
     public Head(){
       icon[0]=new ImageIcon(Head.class.getResource("image/head1.GIF"));
       icon[1]=new ImageIcon(Head.class.getResource("image/head2.GIF"));
 
       setLayout(new FlowLayout(FlowLayout.RIGHT));
       lblHead.setIcon(icon[step]);
       add(lblHead);
       t.start();
     }
     public Dimension getPreferredSize(){
       return new Dimension(50,50);
     }
  }
 
}


瞬间捕捉的图形如下: 



从运行效果上看,因为眼睛、手、脚都没有使用同步机制,所以其运动是没有规律的。现在我们为它加上同步机制,要求按照先动眼睛,再动左手,再动右手,最后动脚的顺序循环播放,更改后的代码如下: 
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
package ql.abs;
 
import java.io.*;
import java.text.*;
import java.util.*;
import java.net.*;
import quanwen.*;    //常用函数
 
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
import javax.swing.border.*;
import java.util.Iterator;
import java.util.List;
 
/**
 * 一个基于线程同步的机器人
 */
public class ExpSync extends JFrame{
  Object headLock = new Object();
  Object arm1Lock = new Object();
  Object arm2Lock = new Object();
  Object legLock = new Object();
 
  JPanel pnlTop=new JPanel(),
         pnlBottom=new JPanel();
 
  JPanel pnlTopLeft=new JPanel(),
         pnlTopRight=new JPanel(),
         pnlTopCenter=new JPanel();
 
  JPanel armLeft=new Arm1(),
         pnlTopLeft2=new JPanel();
 
  JPanel armRight=new Arm2(),
         pnlTopRight2=new JPanel();
 
  JPanel pnlBottomLeft=new JPanel(),
         leg=new Leg(),
         pnlBottomRight=new JPanel();
 
  JPanel head=new Head();
 
 
  Container c;
 
 
  public ExpSync(){
    super("小机器人");
    armLeft.setPreferredSize(new Dimension(50,50));
    pnlTopLeft2.setPreferredSize(new Dimension(50,50));
 
    pnlTopCenter.setBackground(Color.white);
    pnlTopCenter.setPreferredSize(new Dimension(50,50));
    
 
    armRight.setPreferredSize(new Dimension(50,50));
    pnlTopRight2.setPreferredSize(new Dimension(50,50));
 
 
 
    pnlBottomLeft.setPreferredSize(new Dimension(50,50));
    leg.setPreferredSize(new Dimension(50,50));
    pnlBottomRight.setPreferredSize(new Dimension(50,50));
 
 
    c=getContentPane();
    c.setLayout(new GridLayout(3,3,0,0));
    c.add(pnlBottomLeft);
    c.add(head);
    c.add(pnlBottomRight);
    c.add(armLeft);
    c.add(pnlTopCenter);
    c.add(armRight);
    c.add(pnlTopRight2);
    c.add(leg);
    c.add(pnlTopRight);
 
    setSize(167,160);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    show(); 
    //每隔4秒为arm1线程解锁一次
    Arm1Released ar=new Arm1Released();
    ar.start();
  }
  public static void main(String[] args){
    ExpSync exp=new ExpSync();
  }
  //为线程锁链中的左边胳膊解锁
  class Arm1Released extends Thread{
    public void run(){
      while(true){
        try{
          this.sleep(4000);
        }catch(Exception ex){}          
        
        //为arm1解锁
        synchronized(arm1Lock) {
          arm1Lock.notify();
        }                   
        System.out.println("--- Send arm1Lock notify...");       
      }
    }
  }
 
  //左边的胳膊
  class Arm1 extends JPanel{
     ImageIcon[] icon=new ImageIcon[2];
     int step=0;
     JLabel lblArm1=new JLabel();
     Runnable changeIt=new Runnable(){
       public void run(){
         lblArm1.setIcon(icon[step]);
       }
     };
     Thread t=new Thread(){
       public void run(){
         //休眠1秒钟
         while(true){
           System.out.println("arm1 is locked");
           //arm1等待head来解锁
           synchronized (arm1Lock) {
             try {
                arm1Lock.wait();
             } catch (InterruptedException ie) {
                System.out.println(ie.toString());
             }
           }
           System.out.println("arm1 is released");  
 
           SwingUtilities.invokeLater(changeIt);    
 
           try{
             Thread.currentThread().sleep(1000);
           }catch(Exception ex){}          
 
           //arm1为arm2解锁
           synchronized(arm2Lock) {
             arm2Lock.notify();
           }
           System.out.println("--- Send arm2Lock notify...");     
 
 
           step++;
           if(step>1) step=0;
          
         }
       }
     };
     public Arm1(){
       icon[0]=new ImageIcon(Arm1.class.getResource("image/armLeft1.GIF"));
       icon[1]=new ImageIcon(Arm1.class.getResource("image/armLeft2.GIF"));
 
       setLayout(new FlowLayout(FlowLayout.RIGHT));
       lblArm1.setIcon(icon[step]);
       add(lblArm1);
       t.start();
     }
 
     public Dimension getPreferredSize(){
       return new Dimension(50,50);
     }
  }
  class Arm2 extends JPanel{
     ImageIcon[] icon=new ImageIcon[2];
     int step=0;
     JLabel lblArm2=new JLabel();
     Runnable changeIt=new Runnable(){
       public void run(){
         lblArm2.setIcon(icon[step]);
       }
     };
     Thread t=new Thread(){
       public void run(){
         //休眠1秒钟
         while(true){
           System.out.println("arm2 is locked");
           //arm2等待arm1来解锁
           synchronized (arm2Lock) {
             try {
                arm2Lock.wait();
             } catch (InterruptedException ie) {}
           }
           System.out.println("arm2 is released");          
 
           SwingUtilities.invokeLater(changeIt);    
 
           try{
             Thread.currentThread().sleep(1000);
           }catch(Exception ex){}          
 
           //arm2为leg解锁
           synchronized(legLock) {
             legLock.notify();
           }           
           System.out.println("--- Send legLock notify...");       
 
           step++;
           if(step>1) step=0;
         }
       }
     };
 
     public Arm2(){
       icon[0]=new ImageIcon(Arm2.class.getResource("image/armRight1.GIF"));
       icon[1]=new ImageIcon(Arm2.class.getResource("image/armRight2.GIF"));
 
       setLayout(new FlowLayout(FlowLayout.RIGHT));
       lblArm2.setIcon(icon[step]);
       add(lblArm2);
       t.start();
     }
     public Dimension getPreferredSize(){
       return new Dimension(50,50);
     }
  }
  class Leg extends JPanel{
     ImageIcon[] icon=new ImageIcon[2];
     int step=0;
     JLabel lblLeg=new JLabel();
     Runnable changeIt=new Runnable(){
       public void run(){
         lblLeg.setIcon(icon[step]);
       }
     };
     Thread t=new Thread(){
       public void run(){
         //休眠1秒钟
         while(true){
           System.out.println("leg is locked");
           //leg等待arm2来解锁
           synchronized (legLock) {
             try {
                legLock.wait();
             } catch (InterruptedException ie) {}
           }
           System.out.println("leg is released");          
 
           SwingUtilities.invokeLater(changeIt);   
 
           try{
             Thread.currentThread().sleep(1000);
           }catch(Exception ex){}          
 
           //leg为head解锁
           synchronized(headLock) {
             headLock.notify();
           }       
           System.out.println("--- Send headLock notify...");       
   
           step++;
           if(step>1) step=0;
         }
       }
     };
 
     public Leg(){
       icon[0]=new ImageIcon(Leg.class.getResource("image/leg1.GIF"));
       icon[1]=new ImageIcon(Leg.class.getResource("image/leg2.GIF"));
 
       setLayout(new FlowLayout(FlowLayout.RIGHT));
       lblLeg.setIcon(icon[step]);
       add(lblLeg);
       t.start();
     }
     public Dimension getPreferredSize(){
       return new Dimension(50,50);
     }
  }
  class Head extends JPanel{
     ImageIcon[] icon=new ImageIcon[2];
     int step=0;
     JLabel lblHead=new JLabel();
     Runnable changeIt=new Runnable(){
       public void run(){
         lblHead.setIcon(icon[step]);
       }
     };
     Thread t=new Thread(){
       public void run(){
         while(true){
           System.out.println("head is locked");
           //head等待leg来解锁
           synchronized (headLock) {
             try {
                headLock.wait();
             } catch (InterruptedException ie) {}
           }
           System.out.println("head is released");            
 
           SwingUtilities.invokeLater(changeIt);  
 
           try{
             Thread.currentThread().sleep(1000);
           }catch(Exception ex){}          
 
           //head为arm1解锁
           synchronized(arm1Lock) {
             arm1Lock.notify();
           }                   
           System.out.println("--- Send arm1Lock notify...");       
 
           step++;
           if(step>1) step=0;
         }
       }
     };
 
     public Head(){
       icon[0]=new ImageIcon(Head.class.getResource("image/head1.GIF"));
       icon[1]=new ImageIcon(Head.class.getResource("image/head2.GIF"));
 
       setLayout(new FlowLayout(FlowLayout.RIGHT));
       lblHead.setIcon(icon[step]);
       add(lblHead);
       t.start();
     }
     public Dimension getPreferredSize(){
       return new Dimension(50,50);
     }
  }
 
}
 


从代码可以看出。左胳膊Arm1先是阻塞自己,等待Arm1Released线程或Head线程释放自己,当自己被释放以后,则释放Arm2。右胳膊Arm2先是阻塞自己,等待Arm1线程释放自己,当自己被释放以后,则释放leg。腿Leg先是阻塞自己,等待Arm2线程释放自己,当自己被释放以后,则释放head。头Head先是阻塞自己,等待Leg线程释放自己,当自己被释放以后,则释放Arm1。 
因为左胳膊,右胳膊,腿,头三个线程之间不存在先后执行的问题,所以你在实际运行中会看到以下的顺序: 

arm1 is locked 
arm2 is locked 
leg is locked 
head is locked 
--- Send arm1Lock notify --- 1、 Arm1Released线程释放Arm1 
arm1 is released 2、 arm1被Arm1Released释放 
--- Send arm2Lock notify... 3、 arm1释放arm2 
arm1 is locked 
arm2 is released 4、 arm2被arm1释放 
--- Send legLock notify... 5、 arm2释放leg 
arm2 is locked 
leg is released 6、 leg被arm2释放 
--- Send headLock notify... 7、 leg释放head 
leg is locked 
head is released 8、head被leg释放 
--- Send arm1Lock notify... 9、head释放arm1 
head is locked 
arm1 is released 10、arm1被head释放 
--- Send arm1Lock notify --- 11、Arm1Released线程释放Arm1 
--- Send arm2Lock notify... 12、arm1释放arm2 
arm1 is locked 
arm2 is released 13、…… 
--- Send legLock notify... 
arm2 is locked 

程序开始运行构造函数中几个机器人的部件都被初始化,四个部件均被自己阻塞,如果Arm1Released不运行,则四个线程都无法继续工作。即无法执行释放别人的操作而造成整个程序死锁。 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值