Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4562090
  • 博文数量: 1214
  • 博客积分: 13195
  • 博客等级: 上将
  • 技术积分: 9105
  • 用 户 组: 普通用户
  • 注册时间: 2007-01-19 14:41
个人简介

C++,python,热爱算法和机器学习

文章分类

全部博文(1214)

文章存档

2021年(13)

2020年(49)

2019年(14)

2018年(27)

2017年(69)

2016年(100)

2015年(106)

2014年(240)

2013年(5)

2012年(193)

2011年(155)

2010年(93)

2009年(62)

2008年(51)

2007年(37)

分类: Java

2017-09-30 19:24:11

原文:http://www.cnblogs.com/200911/p/3895381.html

上一节售票系统中我们发现,打印出了错票,0,-1,出现了多线程安全问题。我们分析为什么会发生多线程安全问题?

看下面线程的主要代码:

 

复制代码
@Override public void run() { // TODO Auto-generated method stub while(true){ if(ticket > 0){//当线程0被调起的时候,当执行到这条判断语句的时候,线程1被调起抢了CPU资源,线程0进入冻结状态。 try {
                        Thread.sleep(100);//中断当前活跃的线程,或者执行的线程 } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"正在卖票"+ticket--); //System.out.println(Thread.currentThread().getId()); //System.out.println(Thread.currentThread().getName());  }  }
    }
复制代码

分析:当100张票卖到剩余最后1张的时候,也就是ticket=1的时候,有三个线程Thread-0,Thread-1,Thread-2,这时候,Thread-0进入if(ticket > 0)这个条件具备了执行资格,但不具备执行权。正在这个时候,CPU切换到了Thread-1,Thread-1也进入了if(ticket > 0)这个条件下面,CPU又切换到了Thread-2,Thread-2又进入阻塞状态。这个时候三个线程都通过了if(ticket > 0)判断,都要往下执行了,这个时候CPU的资源被Thread-0第一个线程抢到,执行ticket=1,ticket--,那么第一个线程执行完打印出ticket=1,CPU被Thread-2抢到,打印出ticket=0,同理线程3执行完打印出ticket=-1,这就出现了线程安全的问题。

通过上面的分析大家知道了多线程安全产生的原因:当多条语句(if(ticket>0)和ticket--)在操作同一个线程的共享数据的时候(这里共享数据为ticket=100),一个线程执行了多条语句的一部分,还没有执行完,另一个线程抢到CPU资源,执行。导致数据共享错误。那么怎么解决呢?

解决办法:当多条语句在操作共享数据时,只能让一个线程执行完,在执行的过程中,其它线程不可以参与执行。java对于多线程安全问题,提供了专业的解决方法,那就是锁。

synchronized(对象){
         需要被同步的代码
 }

这个“对象”被称为锁,持有锁的线程可以在同步代码块中执行,没有持有锁的线程即使获取到CPU的执行权,也进不去,因为没有获取锁。
 * 火车上的卫生间-经典“

火车售票的问题的解决:代码如下:

复制代码
public class TicketsRunnable implements Runnable { private int ticket=100;  Object obj = new Object();//对象锁,共同步代码块使用 public TicketsRunnable(){
        System.out.println("*****************************");
    }
    @Override public void run() { // TODO Auto-generated method stub while(true){ synchronized(obj){ //同步代码块 if(ticket > 0){//当线程0被调起的时候,当执行到这条判断语句的时候,线程1被调起抢了CPU资源,线程0进入冻结状态。 try {
                        Thread.sleep(100);//中断当前活跃的线程,或者执行的线程 } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"正在卖票"+ticket--); //System.out.println(Thread.currentThread().getId()); //System.out.println(Thread.currentThread().getName());  }  } }
    } /** * @param args */ public static void main(String[] args) {
        TicketsRunnable runna = new TicketsRunnable();
        Thread t1 = new Thread(runna);
        Thread t2 = new Thread(runna);
        Thread t3 = new Thread(runna);
        t1.start();
        t2.start();
        t3.start();
    }

}
复制代码

通过测试,不会出现错票的问题。

分析代码:当火车票剩余1张的时候,这个时候假设Thread-0获取到了CPU的执行权,并且持有对象锁,进入if条件,打印出买票1。ticket--,这个时候即使其他的线程获取到CPU的执行资格,但是设Thread-0的锁还没有释放,其他的线程拿不到锁,这样就进入不了if条件,那么只要等Thread-0执行完,Thread-0执行完后,ticket=0,其他线程即使拿到锁,因为if(ticket > 0)不能进入,所以执行不了。整个程序结束,卖票终止。

总结:通过程序可以知道:同步的前提是:1.必须要有两个或者两个以上的线程,才需要同步。

                                                          2.必须是多个线程使用同一个锁。

                                                          3.要分析哪段代码需要加同步,必须保证同步中只能有一个线程在运行。

同步锁的好处与弊端:1.好处,解决了多线程操作同意资源安全性问题。

                              2.弊端:多个线程每次都需要判断锁,较为消耗资源

阅读(602) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~