多线程临界资源问题

为什么需要“线程同步”
       线程间共享代码和数据可以节省系统开销,提高程序运行效率,但同时也导致了数据的“访问冲突”问题,如何实现线程间的有机交互、并确保共享资源在某些关键时段只能被一个线程访问,即所谓的“线程同步”(Synchronization)就变得至关重要。
临界资源
       多个线程间共享的数据称为临界资源(Critical Resource),由于是线程调度器负责线程的调度,程序员无法精确控制多线程的交替顺序。因此,多线程对临界资源的访问有时会导致数据的不一致行。
互斥锁
       1) 每个对象都对应于一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
       2) Java对象默认是可以被多个线程共用的,只是在需要时才启动“互斥锁”机制,成为专用对象。
       3)关 键字synchronized用来与对象的互斥锁联系
       4) 当某个对象用synchronized修饰时,表明该对象已启动“互斥锁”机制,在任一时刻只能由一个线程访问,即使该线程出现堵塞,该对象的被锁定状态也不会解除,其他线程任不能访问该对象。
synchronized关键字的使用方式有两种:
    使用多线程模拟售票:
    A-----------------

package com.hbsi;
public class SaleTicket {

 /**
  * @param args
  */
 public static void main(String[] args) {
  TestSaleTicket ts=new TestSaleTicket();
  Thread t1=new Thread(ts);
  Thread t2=new Thread(ts);
  t1.start();
  t2.start();
    }
}

class TestSaleTicket implements Runnable{
    private int ticket=100;
 Object obj=new Object();
 public void run() {
  while(true){
   synchronized (obj) {
    if(ticket>0){
     try {
      Thread.sleep(100);
     } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
     System.out.println(Thread.currentThread().getName()+"-----"+ticket--);
    }
   }
   
  }
 }
 
}

  B------------------

package com.hbsi;
public class SaleTicket1 {

 /**
  * @param args
  */
 public static void main(String[] args) {
  SaleTicket2 st=new SaleTicket2();
  Thread t1=new Thread(st);
  Thread t2=new Thread(st);
  t1.start();
  t2.start();
    }
}

class SaleTicket2 implements Runnable{
 private int ticket=100;
 Object obj=new Object();
 public void run(){
  while(true){
   show();
  }
 }
 public synchronized void show(){
  
   if(ticket>0){
   try {
    Thread.sleep(500);
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   System.out.println(Thread.currentThread().getName()+"..."+ticket--);
  
   }
   }

}

      1) 用在对象前面限制一段代码的执行(同步代码块)如A
      2) 用在方法声明中,表示整个方法为同步方法           如B
同步好处: 决了线程安全问题
同步弊端:
      1) 降低了运行效率(判断锁是较为消耗资源的)
      2) 同步嵌套,容易出现死锁
死锁:
      两个线程A、B用到同一个对象s(s为共享资源),且线程A在执行中要用到B运行后所创造的条件。在这种前提下A先开始运行,进入同步块后,对象s被锁定,接着线程A因等待B运行结束而进入阻塞状态,于是B开始运行,但因无法访问对象s,线程B也进入阻塞状态,等待s被线程A解锁。最终的结果:两个线程互相等待,都无法运行。
     如下面的代码就是死锁-----------------
     

package com.hbsi;
public class DeadLock {

 /**
  * @param args
  */
 public static void main(String[] args) {
  Demo6 d1=new Demo6(true);
  Demo6 d2=new Demo6(false);
  Thread t1=new Thread(d1);
  Thread t2=new Thread(d2);
  t1.start();
  t2.start();
 }
}

class MyLock{
 static MyLock lock1=new MyLock();
 static MyLock lock2=new MyLock();
}

class Demo6 implements Runnable{
 //String str1=new String("aaa");
 //String str2=new String("bbb");
 
 private boolean flag;
 public Demo6(boolean flag){
  this.flag=flag;
 }

 @Override
 public void run() {
  if(flag){
   synchronized(MyLock.lock1){
    System.out.println(Thread.currentThread().getName()+"...if...str1"); 
    
    synchronized(MyLock.lock2){
     System.out.println(Thread.currentThread().getName()+"...if...str2");
     
    }
   }
   
   
  }else{
          synchronized(MyLock.lock2){
           System.out.println(Thread.currentThread().getName()+"...else...str2");
          
     synchronized(MyLock.lock1){
     System.out.println(Thread.currentThread().getName()+"...else...str1");
    }
   }
  }
  
 }
 
}

 小总结:Synchronization关键字是一个修饰符,可以修饰方法或代码块。其作用就是:对于同一个对象(不是一个类的不同对象),当多个线程都同时调用该方法或代码块时,必须依次执行,也就是说,如果两个或两个以上的线程同时执行该段代码,如果一个线程已经开始执行该段代码,则另一个线程必须等待这个线程执行完这段代码才能开始执行。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值