synchronized关键字

Java中的每一个对象都有一个内部锁。如果一个方法用synchronized关键字声明,那么对象的锁将保护整个方法。线程进入同步代码块或方法的时候会自动获得该锁,在退出同步代码块或方法时会释放该锁。获得内部锁的唯一途径就是进入这个锁保护的同步代码块或方法。

synchronized关键字主要有修饰代码块和修饰方法两种用法:

1、synchronized关键字修饰一般方法和代码块(使用的是Java对象锁)

public class SynchronizedDemo
{
    //synchronized代码块,锁为this,this代表调用该代码块的当前对象
    public void test1()
    {
        synchronized (this)
        {
            int i = 5;
            while (i-- > 0)
            {
                System.out.println(Thread.currentThread().getName() + " : " + i);
                try
                {
                    Thread.sleep(500);
                }
                catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
            }
        }
    }
    //synchronized修饰方法,锁为调用该方法的对象
    public synchronized void test2()
    {
        int i = 5;
        while (i-- > 0)
        {
            System.out.println(Thread.currentThread().getName() + " : " + i);
            try
            {
                Thread.sleep(500);
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args)
    {
        final SynchronizedDemo demo= new SynchronizedDemo();
        new Thread(new Runnable()
        {
            public void run()
            {
                demo.test1();

            }
        }).start();
        new Thread(new Runnable()
        {
            public void run()
            {
                demo.test2();
            }
        }).start();
    }
}

运行结果为:

Thread-0 : 4
Thread-0 : 3
Thread-0 : 2
Thread-0 : 1
Thread-0 : 0
Thread-1 : 4
Thread-1 : 3
Thread-1 : 2
Thread-1 : 1
Thread-1 : 0

test1()方法里,synchronized修饰代码块,锁为this,this代表调用该代码块的对象。test2()方法上,synchronized修饰方法,锁为调用该方法的对象。所以两个同步代码所需要获得的对象锁都是同一个对象锁。main函数里,两个线程使用的是同一个对象demo来分别调用test1(),test2(),两个线程都需要获得该对象锁,另一个线程必须等待,进入阻塞状态。所以一个线程得到对象锁执行完以后,才会释放锁,然后另一个线程拿到对象锁,开始运行。

那如果main函数里的代码改成下面这样,分别new一个新对象来调用test1()、test2()方法,其他代码不变:

public static void main(String[] args)
    {
        //final SynchronizedDemo demo= new SynchronizedDemo();
        new Thread(new Runnable()
        {
            public void run()
            {
                new SynchronizedDemo().test1();

            }
        }).start();
        new Thread(new Runnable()
        {
            public void run()
            {
                new SynchronizedDemo().test2();
            }
        }).start();
    }
}

运行结果如下:

Thread-0 : 4
Thread-1 : 4
Thread-0 : 3
Thread-1 : 3
Thread-0 : 2
Thread-1 : 2
Thread-0 : 1
Thread-1 : 1
Thread-0 : 0
Thread-1 : 0

可以看到,两个线程交替运行,这是因为调用两个方法的对象并不是同一个对象,所以两个方法得到的对象锁也不是同一个锁。synchronized是用于多个线程来抢夺同一个对象锁的情况,来进行同步。
一个类的对象锁和另一个类的对象锁是没有关联的,当一个线程获得A类的对象锁时,它同时也可以获得B类的对象锁。

2、synchronized关键字修饰静态方法和代码块(使用的是Java类锁)

public class SynchronizedDemo
{
    public void test1()
    {
        synchronized (SynchronizedDemo.class)
        {
            int i = 5;
            while (i-- > 0)
            {
                System.out.println(Thread.currentThread().getName() + " : " + i);
                try
                {
                    Thread.sleep(500);
                }
                catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
            }
        }
    }
    public static synchronized void test2()
    {
        int i = 5;
        while (i-- > 0)
        {
            System.out.println(Thread.currentThread().getName() + " : " + i);
            try
            {
                Thread.sleep(500);
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args)
    {
        new Thread(new Runnable()
        {
            public void run()
            {
                new SynchronizedDemo().test1();

            }
        }).start();
        new Thread(new Runnable()
        {
            public void run()
            {
                SynchronizedDemo.test2();
            }
        }).start();
    }
}

运行结果:

Thread-0 : 4
Thread-0 : 3
Thread-0 : 2
Thread-0 : 1
Thread-0 : 0
Thread-1 : 4
Thread-1 : 3
Thread-1 : 2
Thread-1 : 1
Thread-1 : 0

类锁修饰方法和代码块和对象锁是一样的,因为静态方法是所有对象实例共用的,所以对应着synchronized修饰的静态方法的锁也是唯一的,所以是一个类锁,它的锁对象是本类的class文件,即SynchronizedDemo.class字节码文件,该字节码文件只有一份,被所有的类共用。

那如果synchronized同时修饰静态和非静态方法:

public class SynchronizedDemo
{
    public synchronized void test1()
    {
        int i = 5;
        while (i-- > 0)
        {
            System.out.println(Thread.currentThread().getName() + " : " + i);
            try
            {
                Thread.sleep(500);
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
    }
    public static synchronized void test2()
    {
        int i = 5;
        while (i-- > 0)
        {
            System.out.println(Thread.currentThread().getName() + " : " + i);
            try
            {
                Thread.sleep(500);
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args)
    {
        new Thread(new Runnable()
        {
            public void run()
            {
                new SynchronizedDemo().test1();

            }
        }).start();
        new Thread(new Runnable()
        {
            public void run()
            {
                SynchronizedDemo.test2();
            }
        }).start();
    }
}

运行结果:

Thread-0 : 4
Thread-1 : 4
Thread-1 : 3
Thread-0 : 3
Thread-1 : 2
Thread-0 : 2
Thread-1 : 1
Thread-0 : 1
Thread-1 : 0
Thread-0 : 0

上面代码synchronized同时修饰静态方法和实例方法,但是运行结果是交替进行的,这证明了类锁和对象锁是两个不一样的锁,控制着不同的区域,它们是互不干扰的。同样,线程获得对象锁的同时,也可以获得该类锁,即同时获得两个锁,这是允许的。

总结:所以总的来说,synchronized修饰一般方法时,使用的是调用该方法的对象锁,如果new出来不同的对象来调用该方法,那使用的锁是不一样的,也就没有什么同步可言了。synchronized修饰静态(static)方法时,使用的是该方法所在类的字节码文件,整个内存中只有一份,起到同步的作用,虽然也可以使用new来新建对象调用该静态方法,那其实使用的还是同一个锁对象,但是一般是直接使用类名来调用static方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值