Java多线程使用Synchronized需注意锁的永远是对象

来源:互联网 发布:淘宝优惠券如何领取 编辑:程序博客网 时间:2024/06/01 07:40

最近工作室要给大一刚进来工作室的新生进行Java培训,就把Java的只是重新拿起来复习整理了一遍,一直很忙就一直没有写到博客。
在复习Java多线程这里,在处理线程同步时用到了synchronized,也许是太久没有使用线程,出现了下面的问题(挺菜的问题,不过居然困惑了很久,所以记下来了):

public class TestSynchronized{

    /**     * @param args     */    public static void main(String[] args){        MyBank mb1 = new MyBank();        MyBank mb2 = new MyBank();        mb1.start();        mb2.start();    }

}

class MyBank extends Thread{

private static Integer total = 2000;public void run(){    get1500Dollar();}public synchronized void get1500Dollar(){    if(total > 1500){        times ++;        System.out.println("第" + times + "次取出1500刀:   成功!");        try          {              Thread.sleep(500);          }          catch (InterruptedException e)          {              e.printStackTrace();          }        total -= 1500;    }else{        times ++;        System.out.println("第" + times + "次取出1500刀:   失败!");    }}       

}

这段代码本来是期望能够把让get1500Dollar这个方法在被线程mb1访问到后就不能够被mb2访问到的,结果希望是:

  第1次取出1500刀:成功!  第2次取出1500刀:失败!

然而,事实是:

  第1次取出1500刀:成功!  第2次取出1500刀:成功!

想了很久。。。后来写了个更简单的代码:

public class TestSyc{

public static void main(String[] args){    Example example = new Example();    Thread t1 = new Thread1(example);    Thread t2 = new Thread1(example);    t1.start();    t2.start();}

}

class Example{

public synchronized void execute(){    for (int i = 0; i < 10; ++i)    {        try        {            Thread.sleep(500);        }        catch (InterruptedException e)        {            e.printStackTrace();        }        System.out.println("Hello: " + i);    }}

}

class Thread1 extends Thread
{

private Example example;public Thread1(Example example){    this.example = example;}@Overridepublic void run(){    example.execute();}

}

这时,我才想起,synchronized加锁永远都是对对象加锁这一句话,这才理清了思路,对于第二个程序,Example类里面的方法execute加了synchronized之后,t1调用了这个方法后,就对获得这个方法的对象进行了加锁,即对new出来的example整个对象进行加锁了,所以t2想要去通过example访问到execute这个方法就是不可能的了。这个锁会对对象的所有成员变量与方法起作用,也会对这个对象所属类的静态域以及静态方法起作用;但不会由锁住同一个类实例化出来的对象的成员变量和非静态方法。其他由然后回到第一个程序,我是把get1500Dollar方法放在了我的MyBank这个线程类里面,我实例化了mb1,和mb2两个实例,他们的非静态方法并不会互相影响,所以我mb1调用了get1500Dollar时是锁住了mb1这个对象,而我mb2调用的get1500Dollar方法则是mb2自己的方法,所以当然可以被正常访问。
因此,解决方法就是:
1. 把get1500Dollar声明为static,即静态方法;
2. 使用synchronized块,锁住MyBank里面的静态变量total,如下:

public void get1500Dollar(){    synchronized (total)    {        if(total > 1500){            times ++;            System.out.println("第" + times + "取出1500刀: 成功!");            try            {                Thread.sleep(500);            }            catch (InterruptedException e)            {                e.printStackTrace();            }            total -= 1500;        }else{            times ++;            System.out.println("第" + times + "取出1500刀: 失败!");        }    }}
0 0
原创粉丝点击