同步锁、互锁(死锁)

      经历了精心动魄的考试系统之后,对锁、多线程的理解进一步加深了,记得在单例模式的时候接触过一点,但那都是皮毛,简单的理解,还是实践后对问题理解的深刻,接下来和大家共同分享学习。


死锁的问题出现

       cpu分给每个线程的时间片是随机的并且有好多都是多个线程共用一个资源,比如现在我们很多的抢火车卖票,火车票是一定的,但卖火车票的窗口到处都有,每个窗口就相当于一个线程,这么多的线程共用所有的火车票这个资源。如果在一个时间点上,两个线程同时使用这个资源,那他们取出的火车票是一样的(座位号一样),这样就会给乘客造成麻烦。比如下面程序:


package com.dr.runnable2;
class TicketSouce implements Runnable
{
    //票的总数
    private int ticket=10;
    public void run()
    {
        for(int i=1;i<50;i++)
        {
            if(ticket>0)
            {
                //休眠1s秒中,为了使效果更明显,否则可能出不了效果
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"号窗口卖出"+this.ticket--+"号票");
            }
        }
    }
}
public class Test {
    public static void main(String args[])
    {
        TicketSouce mt=new TicketSouce();
        //基于火车票创建三个窗口
        new Thread(mt,"a").start();
        new Thread(mt,"b").start();
        new Thread(mt,"c").start();
    } 

} 

全国这么多售票窗口就会出现以下结果:

图示1:

同步锁、互锁(死锁)


       我们可以看到a号窗口和和c号窗口都卖出了7号票,并且a号和c号窗口分别卖出了0号和-1号票。造成这种情况的原因是1、a线程和b线程在ticket=7的时候,a线程取出7号票以后,ticket还没来的及减1b线程就取出了ticket此时ticket还等于7;2、在ticket=1时,b线程取出了1号票,ticket还没来的及减1,a、c线程就先后进入了if判断语句,这时ticket减1了,那么当a、c线程取票的时候就取到了0号和-1号票。( 前一段报的网上有一样的火车票,一种是锁没有控制好,多线程引发问题,另一个原因就是有假票吧)

   

如何解决死锁?

       出现了上述情况怎样改变呢,我们可以这样做:当一个线程要使用火车票这个资源时,我们就交给它一把锁,等它把事情做完后在把锁给另一个要用这个资源的线程。这样就不会出现上述情况。 实现这个锁的功能就需要用到(java中)synchronized这个关键字。


         synchronized这个关键字有两种用法1、放方法名前形成同步方法;2、放在块前构成同步块。


package com.dr.runnable2;
class TicketSouce implements Runnable
{
    //票的总数
    private int ticket=10;
    public void run()
    {
        for(int i=1;i<50;i++)
        {
            try {
                //休眠1s秒中,为了使效果更明显,否则可能出不了效果
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            this.sale();
        }
    }
    public synchronized void sale()
    {
            if(ticket>0)
            {
                System.out.println(Thread.currentThread().getName()+"号窗口卖出"+this.ticket--+"号票");
            }
    }
}
public class Test {
    public static void main(String args[])
    {
        TicketSouce mt=new TicketSouce();
        //基于火车票创建三个窗口
        new Thread(mt,"a").start();
        new Thread(mt,"b").start();
        new Thread(mt,"c").start();
    } 

}



图片2:


同步锁、互锁(死锁)


c#当中:同步锁实例


Public NotInheritable Class Singleton 
    Shared m_instance As Singleton = Nothing
    Shared ReadOnly padlock As New Object() 
  
    Private Sub New() 
    End Sub
  
    Public Shared ReadOnly Property Instance() As Singleton 
        Get
            SyncLock  padlock 
                If m_instance Is Nothing Then
                    m_instance = New Singleton() 
                End If
                Return m_instance 
            End SyncLock
        End Get
    End Property
End Class


        同步锁是一个线程先做,其他等待第一个释放后再接着做,就不会发生死锁的现象。

        另一个小实例: A,B线程,同步资源C,D ,A线程锁定一个C资源并试图访问D资源,B线程锁定一个D资源并试图访问C资源,两个相互等待就造成了死锁,如同考试系统中的抽不出题,没有任何反应。


总结

        引起多线程问题的原因很多(静态成员变量的慎用),如果在类成员函数中使用了私有的静态成员变量,则该变量会在类的多个实例间共享,而不仅仅是一个实例内共享,但是在同一个时刻它只有一份,当多线程执行时,它会产生微妙的变化,线程之间的取传值都造成了影响,这样就造成了多线程的死锁,产生一些自己不可预知的错误,强大的数据量测试可以测试出很多的问题。多线程高并发的问题值得我们以后考虑要深刻,另一个角度来看,测试工作很是重要、很有学问的一门课啊。

同步锁、互锁(死锁)

上一篇:Java线程_Notify,NotifyAll,Wait方法


下一篇:如何定义深度未知的层次结构