synchronized的作用

synchronized的作用 
一、同步方法
public synchronized void methodAAA(){

//….

}
锁定的是调用这个同步方法的对象

测试:
a、不使用这个关键字修饰方法,两个线程调用同一个对象的这个方法。
目标类:

1 ExpandedBlockStart.gif ContractedBlock.gif public   class  TestThread  dot.gif {
2ExpandedSubBlockStart.gifContractedSubBlock.gif    public  void execute()dot.gif{  //synchronized,未修饰
3ExpandedSubBlockStart.gifContractedSubBlock.gif        for(int i=0;i<100;i++)dot.gif{
4InBlock.gif            System.out.println(i);
5ExpandedSubBlockEnd.gif        }
    
6ExpandedSubBlockEnd.gif    }

7ExpandedBlockEnd.gif}


线程类:

1 ExpandedBlockStart.gif ContractedBlock.gif public   class  ThreadA  implements  Runnable dot.gif {
2InBlock.gif    TestThread test=null;
3ExpandedSubBlockStart.gifContractedSubBlock.gif    public ThreadA(TestThread pTest)dot.gif{  //对象有外部引入,这样保证是同一个对象
4InBlock.gif        test=pTest;
5ExpandedSubBlockEnd.gif    }

6ExpandedSubBlockStart.gifContractedSubBlock.gif    public void run() dot.gif{
7InBlock.gif        test.execute();
8ExpandedSubBlockEnd.gif    }

9ExpandedBlockEnd.gif}

调用:
1 None.gif TestThread test = new  TestThread();
2 None.gifRunnable runabble = new  ThreadA(test);
3 None.gifThread a = new  Thread(runabble, " A " );                
4 None.gifa.start();
5 None.gifThread b = new  Thread(runabble, " B " );
6 None.gifb.start();


结果:
输出的数字交错在一起。说明不是同步的,两个方法在不同的线程中是异步调用的。

b、修改目标类,增加synchronized修饰

1 ExpandedBlockStart.gif ContractedBlock.gif public   class  TestThread  dot.gif {
2ExpandedSubBlockStart.gifContractedSubBlock.gif    public synchronized  void execute()dot.gif{  //synchronized修饰
3ExpandedSubBlockStart.gifContractedSubBlock.gif        for(int i=0;i<100;i++)dot.gif{
4InBlock.gif            System.out.println(i);
5ExpandedSubBlockEnd.gif        }
    
6ExpandedSubBlockEnd.gif    }

7ExpandedBlockEnd.gif}


结果:
输出的数字是有序的,首先输出A的数字,然后是B,说明是同步的,虽然是不同的线程,但两个方法是同步调用的。
注意:上面虽然是两个不同的线程,但是是同一个实例对象。下面使用不同的实例对象进行测试。

c、每个线程都有独立的TestThread对象。
目标类:

1 ExpandedBlockStart.gif ContractedBlock.gif public   class  TestThread  dot.gif {
2ExpandedSubBlockStart.gifContractedSubBlock.gif    public synchronized void execute()dot.gif{  //synchronized修饰
3ExpandedSubBlockStart.gifContractedSubBlock.gif        for(int i=0;i<100;i++)dot.gif{
4InBlock.gif            System.out.println(i);
5ExpandedSubBlockEnd.gif        }
    
6ExpandedSubBlockEnd.gif    }

7ExpandedBlockEnd.gif}

线程类:
1 ExpandedBlockStart.gif ContractedBlock.gif public   class  ThreadA  implements  Runnable dot.gif {
2ExpandedSubBlockStart.gifContractedSubBlock.gif    public void run() dot.gif{
3InBlock.gif        TestThread test=new TestThread();
4InBlock.gif        test.execute();
5ExpandedSubBlockEnd.gif    }

6ExpandedBlockEnd.gif}

7 None.gif

调用:
1 None.gif Runnable runabble = new  ThreadA();
2 None.gifThread a = new  Thread(runabble, " A " );                
3 None.gifa.start();
4 None.gifThread b = new  Thread(runabble, " B " );
5 None.gifb.start();


结果:
输出的数字交错在一起。说明虽然增加了synchronized 关键字来修饰方法,但是不同的线程调用各自的对象实例,两个方法仍然是异步的。

引申:
对于这种多个实例,要想实现同步即输出的数字是有序并且按线程先后顺序输出,我们可以增加一个静态变量,对它进行加锁(后面将说明锁定的对象)。

修改目标类:

 1 ExpandedBlockStart.gif ContractedBlock.gif public   class  TestThread  dot.gif {
 2InBlock.gif    private static Object lock=new Object(); //必须是静态的。
 3ExpandedSubBlockStart.gifContractedSubBlock.gif    public  void execute()dot.gif{
 4ExpandedSubBlockStart.gifContractedSubBlock.gif        synchronized(lock)dot.gif{
 5ExpandedSubBlockStart.gifContractedSubBlock.gif            for(int i=0;i<100;i++)dot.gif{
 6InBlock.gif                System.out.println(i);
 7ExpandedSubBlockEnd.gif            }
    
 8ExpandedSubBlockEnd.gif        }

 9ExpandedSubBlockEnd.gif    }

10ExpandedBlockEnd.gif}

二、同步代码块

1 ExpandedBlockStart.gif ContractedBlock.gif public   void  method(SomeObject so) dot.gif {
2InBlock.gif    synchronized(so)
3InBlock.gif       //…..
4ExpandedBlockEnd.gif    }

5 None.gif}

锁定一个对象,其实锁定的是该对象的引用(object reference)
谁拿到这个锁谁就可以运行它所控制的那段代码。当有一个明确的对象作为锁时,就可以按上面的代码写程序,但当没有明确的对象作为锁,只是想让一段代码同步时,可以创建一个特殊的instance变量(它必须是一个对象)来充当锁(上面的解决方法就是增加了一个状态锁)。

a、锁定一个对象,它不是静态的
private byte[] lock = new byte[0]; // 特殊的instance变量
目标类:

 1 ExpandedBlockStart.gif ContractedBlock.gif public   class  TestThread  dot.gif {
 2InBlock.gif    private Object lock=new Object(); 
 3ExpandedSubBlockStart.gifContractedSubBlock.gif    public  void execute()dot.gif{
 4ExpandedSubBlockStart.gifContractedSubBlock.gif        synchronized(lock)dot.gif{  //增加了个锁,锁定了对象lock,在同一个类实例中,是线程安全的,但不同的实例还是不安全的。
 5InBlock.gif
 6InBlock.gif因为不同的实例有不同对象锁lock
 7ExpandedSubBlockStart.gifContractedSubBlock.gif            for(int i=0;i<100;i++)dot.gif{
 8InBlock.gif                System.out.println(i);
 9ExpandedSubBlockEnd.gif            }
    
10ExpandedSubBlockEnd.gif        }

11ExpandedSubBlockEnd.gif    }

12ExpandedBlockEnd.gif}
  


其实上面锁定一个方法,等同于下面的:

1 ExpandedBlockStart.gif ContractedBlock.gif public   void  execute() dot.gif {  
2ExpandedSubBlockStart.gifContractedSubBlock.gif    synchronized(this)dot.gif{   //同步的是当然对象
3ExpandedSubBlockStart.gifContractedSubBlock.gif        for(int i=0;i<100;i++)dot.gif{
4InBlock.gif            System.out.println(i);
5ExpandedSubBlockEnd.gif        }
    
6ExpandedSubBlockEnd.gif    }

7ExpandedBlockEnd.gif}

b、锁定一个对象或方法,它是静态的
这样锁定,它锁定的是对象所属的类
public synchronized  static void execute(){
    //...
}
等同于

1 ExpandedBlockStart.gif ContractedBlock.gif public   class  TestThread  dot.gif {
2ExpandedSubBlockStart.gifContractedSubBlock.gif    public static void execute()dot.gif{
3ExpandedSubBlockStart.gifContractedSubBlock.gif        synchronized(TestThread.class)dot.gif{
4InBlock.gif            //dot.gif
5ExpandedSubBlockEnd.gif        }

6ExpandedSubBlockEnd.gif    }

7ExpandedBlockEnd.gif}

测试:

目标类:

 1 ExpandedBlockStart.gif ContractedBlock.gif public   class  TestThread  dot.gif {
 2InBlock.gif    private static Object lock=new Object();
 3ExpandedSubBlockStart.gifContractedSubBlock.gif    public synchronized static void execute()dot.gif{  //同步静态方法
 4ExpandedSubBlockStart.gifContractedSubBlock.gif        for(int i=0;i<100;i++)dot.gif{
 5InBlock.gif            System.out.println(i);
 6ExpandedSubBlockEnd.gif        }
    
 7ExpandedSubBlockEnd.gif    }

 8ExpandedSubBlockStart.gifContractedSubBlock.gif    public static void execute1()dot.gif{
 9ExpandedSubBlockStart.gifContractedSubBlock.gif        for(int i=0;i<100;i++)dot.gif{
10InBlock.gif            System.out.println(i);
11ExpandedSubBlockEnd.gif        }
    
12ExpandedSubBlockEnd.gif    }

13ExpandedSubBlockStart.gifContractedSubBlock.gif    public void test()dot.gif{
14InBlock.gif        execute();     //输出是有序的,说明是同步的
15InBlock.gif        //execute1();  //输出是无须的,说明是异步的
16ExpandedSubBlockEnd.gif    }

17ExpandedBlockEnd.gif}

线程类:调用不同的方法,于是建立了两个线程类

 1 ExpandedBlockStart.gif ContractedBlock.gif public   class  ThreadA  implements  Runnable dot.gif {
 2ExpandedSubBlockStart.gifContractedSubBlock.gif    public void run() dot.gif{
 3InBlock.gif        TestThread.execute();//调用同步静态方法
 4ExpandedSubBlockEnd.gif    }

 5ExpandedBlockEnd.gif}

 6 ExpandedBlockStart.gifContractedBlock.gif public   class  ThreadB  implements  Runnable dot.gif {
 7ExpandedSubBlockStart.gifContractedSubBlock.gif    public void run() 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值