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

最近工作室要给大一刚进来工作室的新生进行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;
}

@Override
public 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刀: 失败!");
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值