Java的synchronized使用小结

首先需要阐明两个基本问题:1.锁只能获取自对象,而不是代码,也就是说synchronized [static] methodName这样的写法其实获取的还是对象锁;2.未synchronized的代码执行不受锁的影响。

下面看synchronized的使用场景:

1.synchronized非静态方法和synchronized(this)

这是等效的两种写法,也就是说synchronized非静态方法其实获取的是this对象锁。

当多个线程操作同一实例时,任一线程调用任一synchronized非静态方法均会阻塞其余线程对所有synchronized非静态方法的调用,也就是说所有线程对synchronized非静态方法的调用将变成串行。当不同线程操作不同实例时,对synchronized非静态方法的调用将变成并行。

class SyncTest
{
    public void nonStaticA()
    {
        synchronized (this)
        {
            for (int i = 0; i < 5; ++i)
            {
                System.out.println(Thread.currentThread().getName() + " nonStaticA");
                Thread.sleep(100);
            }
        }
    }

    public synchronized void nonStaticB()
    {
        for (int i = 0; i < 5; ++i)
        {
            System.out.println(Thread.currentThread().getName() + " nonStaticB");
            Thread.sleep(100);
        }
    }

    ......
}
假设SyncTest对象obj,线程T1调用obj#nonStaticA,线程T2调用obj#nonStaticB,后者调用的执行必须在前者完成之后。

2.synchronized静态方法和synchronized(class)
这是等效的两种写法,也就是说synchronized静态方法其实获取的是class对象锁。
当多个线程操作任意实例时,任一线程调用任一synchronized静态方法均会阻塞其余线程对所有synchronized静态方法的调用,也就是说所有线程对synchronized静态方法的调用将变成串行。

class SyncTest
{
    public void staticA()
    {
        synchronized (SyncTest.class)
        {
            for (int i = 0; i < 5; ++i)
            {
                System.out.println(Thread.currentThread().getName() + " staticA");
                Thread.sleep(100);
            }
        }
    }

    public synchronized static void staticB()
    {
        for (int i = 0; i < 5; ++i)
        {
            System.out.println(Thread.currentThread().getName() + " staticB");
            Thread.sleep(100);
        }
    }

    ......
}
假设线程T1调用SyncTest#staticB,线程T2调用obj#staticA,后者调用的执行必须在前者完成之后。

3.synchronized非静态方法和synchronized静态方法共存
当多个线程操作同一实例时,任一线程调用任一synchronized非静态方法均不阻塞其余线程对所有synchronized静态方法的调用,反之亦然,也就是说这两者彼此不影响。
结合上述的SyncTest代码,假设线程T1调用obj#nonStaticB,线程T2调用SyncTest#staticB,两者会并发执行。

4.synchronized非静态成员变量
这个本质与1一样,只不过是锁的作用区域变小了,一般是方法体内的代码块。
当多个线程操作同一实例时,任一线程执行synchronized(lockObj)代码块时,均会阻塞其余线程对所有的synchronized(lockObj)代码块的执行,也就是说所有线程对synchronized(lockObj)代码块的执行将变成串行。注意:此处的synchronized(lockObj)表示获取名称为lockObj的非static对象的锁,如果类代码中还有其余对象锁的话,彼此不受影响。当然,如果不同线程针对不同实例的话,也相互没有影响。

class SyncTest
{
    private final Object lock = new Object();

    public void lockMethodA()
    {
	......

        synchronized (lock)
        {
            for (int i = 0; i < 5; ++i)
            {
                System.out.println(Thread.currentThread().getName() + " lockMethodA");
                Thread.sleep(100);
            }
        }

	......
    }

    ......
}
假设SyncTest对象obj,线程T1调用obj#lockMethodA,线程T2调用obj#lockMethodA,前者将在synchronized (lock)处阻塞后者。如果T2调用obj#nonStaticB,两个线程彼此没有影响。注意:obj#nonStaticB获取的是this对象锁,obj#lockMethodA获取的是lock对象锁,虽然lock是this的成员变量,但是作为对象锁时彼此没有影响。

5.synchronized静态成员变量
这个本质与2一样,也只不过是锁的作用区域变小为方法体内的代码块。
当多个线程操作任一实例时,任一线程执行synchronized(lockObj)代码块时,均会阻塞其余线程对所有的synchronized(lockObj)代码块的执行,也就是说所有线程对synchronized(lockObj)代码块的执行将变成串行。注意:此处的synchronized(lockObj)表示获取名称为lockObj的static对象的锁,如果类代码中还有其余对象锁的话,彼此不受影响。

class SyncTest
{
    private final static Object lockStaticA = new Object();

    private final static Object lockStaticB = new Object();

    public void lockStaticMethodA()
    {
	......

       synchronized (lockStaticA)
        {
            for (int i = 0; i < 5; ++i)
            {
                System.out.println(Thread.currentThread().getName() + " lockMethodA");
                try
                {
                    Thread.sleep(100);
                }
                catch (final InterruptedException e)
                {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }

	......
    }

    public void lockStaticMethodB()
    {
	......

        synchronized (lockStaticB)
        {
            for (int i = 0; i < 5; ++i)
            {
                System.out.println(Thread.currentThread().getName() + " lockStaticMethodB");
                try
                {
                    Thread.sleep(100);
                }
                catch (final InterruptedException e)
                {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }

	......
    }

    ......
}
假设线程T1调用obj#lockStaticMethodA,线程T2调用obj1#lockStaticMethodA,前者将在synchronized(lockStaticA)处阻塞后者。但如果T2调用obj#lockStaticMethodB,将不受影响。

上面应该囊括了synchronized的绝大部分使用场景,不过这么累赘的描述其实可以简单的归类到两种大场景:获取锁的对象是静态还是非静态。如果是非静态,则只有操作同一实例的线程,在执行synchronized的代码区域时,会竞争指定的对象锁。如果是静态,则操作任一实例的线程,在执行synchronized的代码区域时,会竞争指定的对象锁。

最后再强调一下:不同的对象锁之间不受影响。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值