森森快跑

走得累,走得苦,那是因为在走上坡路。
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Java学习(十一):Java锁Synchronized,对象锁和类锁举例

Posted on 2015-04-04 19:20  森森快跑  阅读(4948)  评论(0编辑  收藏  举报

  Java的锁分为对象锁和类锁。

  1. 当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内针对该对象的操作只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。

  2. 然而,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。

  3. 尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对该object中所有其它synchronized(this)同步代码块的访问将被阻塞。

  4. 同步加锁的是对象,而不是代码。因此,如果你的类中有一个同步方法,这个方法可以被两个不同的线程同时执行,只要每个线程自己创建一个的该类的实例即可。

  5. 不同的对象实例的synchronized方法是不相干扰的。也就是说,其它线程照样可以同时访问相同类的另一个对象实例中的synchronized方法。

  6. synchronized关键字是不能继承的,也就是说,基类的方法synchronized f(){} 在继承类中并不自动是synchronized f(){},而是变成了f(){}。继承类需要你显式的指定它的某个方法为synchronized方法。

  7.对一个全局对象或者类加锁时,对该类的所有对象都起作用。

 

类锁举例

普通锁:

 

package ceshi;

public class MySynchronized extends Thread
{
    private int val;
    
    private Object lock = new Object();
    
    public MySynchronized(int v)
    {
        val = v;
    }
    
    public void printVal(int v)
    {
        synchronized (lock)
        {
            for (int i = 0; i < 50; i++)
            {
                System.out.print(v);
            }
        }
    }
    
    public void run()
    {
        printVal(val);
    }
    
    public static void main(String args[])
    {
        MySynchronized f1 = new MySynchronized(1);
        f1.start();
        MySynchronized f2 = new MySynchronized(2);
        f2.start();
    }
}

 

执行结果:2222211111111211111211111111111111111111111111112111111111222222222222222222222222222222222222222222

尽管printVal()对lock变量加锁,但f1和f2是不同的对象,此时这种锁在不同的对象之间不起作用。

 

 

对一个全局变量加锁:

 

 1 package ceshi;
 2 
 3 public class MySynchronized extends Thread
 4 {
 5     private int val;
 6     
 7     private static Object lock = new Object();
 8     
 9     public MySynchronized(int v)
10     {
11         val = v;
12     }
13     
14     public void printVal(int v)
15     {
16         synchronized (lock)
17         {
18             for (int i = 0; i < 50; i++)
19             {
20                 System.out.print(v);
21             }
22         }
23     }
24     
25     public void run()
26     {
27         printVal(val);
28     }
29     
30     public static void main(String args[])
31     {
32         MySynchronized f1 = new MySynchronized(1);
33         f1.start();
34         MySynchronized f2 = new MySynchronized(2);
35         f2.start();
36     }
37 }

 

运行后输出:1111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222

或者2222222222222222222222222222222222222222222222222211111111111111111111111111111111111111111111111111

由于有全局变量加锁,尽管是两个不同的变量f1和f2,printVal()只能依次执行,数字1和2不会同时输出。

 

 

对整个类加锁:

 

package ceshi;

public class MySynchronized extends Thread
{
    private int val;
    
    private static Object lock = new Object();
    
    public MySynchronized(int v)
    {
        val = v;
    }
    
    public void printVal(int v)
    {
        synchronized (MySynchronized.class)
        {
            for (int i = 0; i < 50; i++)
            {
                System.out.print(v);
            }
        }
    }
    
    public void run()
    {
        printVal(val);
    }
    
    public static void main(String args[])
    {
        MySynchronized f1 = new MySynchronized(1);
        f1.start();
        MySynchronized f2 = new MySynchronized(2);
        f2.start();
    }
}

 

输出同上

 

 

另外的锁例子:

 1 public class MySynchronized extends Thread
 2 {
 3     private String name;
 4     
 5     private String val;
 6     
 7     public MySynchronized(String name, String v)
 8     {
 9         this.name = name;
10         val = v;
11     }
12     
13     public void printVal()
14     {
15         synchronized (val)
16         {
17             while (true)
18             {
19                 System.out.println(name + val);
20             }
21         }
22     }
23     
24     public void run()
25     {
26         printVal();
27     }
28     
29     public static void main(String args[])
30     {
31         MySynchronized f1 = new MySynchronized("Foo 1:", "printVal");
32         f1.start();
33         MySynchronized f2 = new MySynchronized("Foo 2:", "printVal");
34         f2.start();
35     }
36 }
View Code

String常量的特殊性,属于同一个对象。