最近工作室要给大一刚进来工作室的新生进行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刀: 失败!");
}
}
}