多线程之间的同步控制

问题:


同时运行的几个线程需要共享一个数据,并且要考虑到彼此的状态和动作。


例如,当一个线程对共享的数据进行操作时,在没有完成相关操作之前,不允许其他线程打断它,否则会破坏数据的完整性。也就是说,被多个线程共享的数据在同一时刻只允许一个线程处于操作之中。

  

实现原理:


    为了保证线程安全,使用“锁旗标”;

当线程A获得了一个对象的锁旗标后,线程B若也想获得该对象的锁旗标,就必须等待线程A完成规定的操作并释放出锁旗标后,才能获得该对象的锁旗标,并执行线程B中的操作。



代码实现:


[java]  view plain copy
  1. public class ProducerAndConsumer {  
  2.   
  3.     /** 
  4.      * 假定开始售票处并没有票,一个线程往里存票,另一个线程则往外卖票。 
  5.      * 新建一个票类对象,让存票和售票线程都访问它。 
  6.      * 两个线程共享同一个数据对象来实现对同一份数据的操作 
  7.      */  
  8.     public static void main(String[] args) {  
  9.         Tickets t=new Tickets(10); //新建一个票类对象,总票数作为参数  
  10.         new Producer(t).start(); //以票类对象为参数创建存票线程对象,并启动  
  11.         new Consumer(t).start();//以同一个票类对象为参数创建售票线程,并启动  
  12.   
  13.     }  
  14.   
  15. }  
  16.   
  17. //票类  
  18. class Tickets{  
  19.     int number=0//票号  
  20.     int size;   //总票数  
  21.     boolean available=false//表示目前是否有票可售  
  22.     public Tickets(int size){this.size=size;}//构造函数,传入总票数参数  
  23. }  
  24.   
  25. //存票线程  
  26. class Producer extends Thread{  
  27.     Tickets t=null;  
  28.     public Producer(Tickets t){this.t=t;}//构造函数:以一个票类为参数  
  29.     @Override  
  30.     public void run() {  
  31.         while(t.number<t.size){//限制循环条件为存票序号小于总票数  
  32.             synchronized(t){//申请对象t的锁旗标  
  33.                 System.out.println("Producer puts ticket "+(++t.number));  
  34.                 t.available=true;//可以买票  
  35.             }//自动释放锁旗标  
  36.               
  37.         }  
  38.     }  
  39. }  
  40.   
  41. //售票线程  
  42. class Consumer extends Thread{  
  43.     Tickets t=null;  
  44.     int i=0;  
  45.     public Consumer(Tickets t){//构造函数:以一个票类对象为参数  
  46.         this.t=t;  
  47.     }  
  48.     public void run(){  
  49.           
  50.         synchronized(t){  
  51.             while(i<t.size){ //循环条件为售票序号小于总票数  
  52.                 if(t.available==true && i<=t.number){ //有票可售且小于目前票序号  
  53.                     System.out.println("consumer buys ticket "+(++i));  
  54.                 }  
  55.                 if(i==t.number){//当票已售到当前序号,则不可售  
  56.                     t.available=false;  
  57.                 }  
  58.             }  
  59.         }  
  60.           
  61.     }  
  62. }  


       一个对象的锁旗标只有一个,所以利用对一个对象锁旗标的争夺,可以实现不同线程的互斥效果。当一个线程获得锁旗标后,需要改锁旗标的其他线程只能处于等待状态。


      另外, 也可以将此关键字加在方法上:


[java]  view plain copy
  1. //取票方法  
  2.     public synchronized void sell(){  
  3.         if(!available){ //如果没有存票,则售票线程等待  
  4.             try{  
  5.                 wait();  
  6.             }  
  7.             catch(Exception e){  
  8.                   
  9.             }  
  10.             System.out.println("consumer buys ticket "+(number));  
  11.             available=false;  
  12.             notify();//售票唤醒存票线程开始存票  
  13.             if(number==size){  
  14.                 number=size+1;//在售完最后一张票后,设置一个结束标志  
  15.             }//number>size表示售票结束  
  16.         }  
  17.     }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值
>