码迷,mamicode.com
首页 > 编程语言 > 详细

Java---13---多线程:解决多线程的安全问题---synchronized 同步代码块

时间:2014-12-14 17:16:53      阅读:128      评论:0      收藏:0      [点我收藏+]

标签:多线程   安全   synchronized   同步   

还是之前卖票的例子:


class Test implements Runnable
{
    private int num = 50;
    Object obj = new Object();
    public void run ()
    {
        while (true)
        {
            if (num >= 0)
            {
                try
                {
                    Thread.sleep(20);
                }
                catch (Exception e)
                {
                    // TODO: handle exception
                    System.out.println(e.toString());
                }
                System.out.println(Thread.currentThread().getName()+">>"+num--);
            }
        }
    }
}


public class RUNNABLE
{
    public static void main (String[] args)
    {
        Test t = new Test();
        Thread a = new Thread(t);
        Thread b = new Thread(t);
        Thread c = new Thread(t);
        Thread d = new Thread(t);

        a.start();
        b.start();
        c.start();
        d.start();
    }
}


在打印结果发现出现了 -1,-2,这与实际是不相符的,也许你会有疑问,不是num >= 0的时候才输出结果的吗,为什么会出现负数呢?

这就是多线程的安全问题。

 

解释一下:

当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行,导致共享数据的错误。

假如说输出结果是这样的:

Thread-2...0

Thread-0...-1

Thread-3...-2

可能造成这样的结果的原因是:

当num=0的时候0线程来了,睡了,3线程来了,也睡了,这个时候2线程sleep的时间到了,醒过来了,这时2线程执行程序,输出结果为0,之后0线程和3线程醒了过来,然后它们接着执行程序,不需要再判断num是否符合条件,因为在它们睡之前就已经判断过了,所以再输出结果的时候,num的值已经变为负数了。这就是会输出负数的原因。

 

解决办法:

对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可参与。

对于多线程的解决方式:同步代码块

格式:

synchronized (对象)
{
    //需要被同步的语句
}


解决方案:


class Test implements Runnable
{
    private int num = 50;
    Object obj = new Object();
    public void run ()
    {
        while (true)
        {
            synchronized (obj)
            {
                if (num >= 0)
                {
                    try
                    {
                        Thread.sleep(20);
                    }
                    catch (Exception e)
                    {
                        // TODO: handle exception
                        System.out.println(e.toString());
                    }
                    System.out.println(Thread.currentThread().getName()+">>"+num--);
                }
            }
        }
    }
}


public class RUNNABLE
{
    public static void main (String[] args)
    {
        Test t = new Test();
        Thread a = new Thread(t);
        Thread b = new Thread(t);
        Thread c = new Thread(t);
        Thread d = new Thread(t);

        a.start();
        b.start();
        c.start();
        d.start();
    }
}


哪些代码需要被同步就要看哪些语句在操作共享数据。


 

同步代码块的工作原理:

 synchronized (obj)

{

    //被同步的代码

}

 

在需要被同步的代码外加了synchronized(obj) 就相当于将需要被同步的代码关进了一个房间,obj就相当于这个房间的锁,一开始默认这个锁是打开的,当某一个线程需要执行被同步的代码的时候,需要先判断能不能进入到这个房间,也就是这个锁是不是打开的。如果锁是打开的,那么这个线程就会进入到房间里,从而执行被同步的代码,顺便把锁锁上了,锁上之后,别的线程如果也要运行被同步的代码的时候,也需要先判断能不能进去,但这个时候的锁是锁上的,也就是说,别的线程进不去。也就是说,只要有线程在执行被同步的代码的时候,别的线程是无法再执行的。当线程执行完了被同步的代码的时候,出去这个房间的时候,就将锁打开了,这个时候,其他的线程才有机会进入到这个房间执行代码。

 

同步的前提:

1.必须是两个及两个以上的线程

就一个线程就不需要锁了,所有的代码都是它来执行

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

意思就是多个线程都进一个房间,如果每个线程进入各自对应的房间,锁与不锁又有什么区别

保证房间内只有一个线程

 

 

好处:解决安全性问题

弊端:线程在执行代码的时候需要判断锁,消耗了一定的资源。



Java---13---多线程:解决多线程的安全问题---synchronized 同步代码块

标签:多线程   安全   synchronized   同步   

原文地址:http://blog.csdn.net/u013476556/article/details/41926045

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!