并发编程(8)synchronized的用法

       上一篇中我们讨论了线程安全问题,了解了解决线程安全问题的主要两种方式,今天来探讨一下通过同步互斥方式,在java中提供了两种方式来实现同步互斥访问:synchronized和Lock,今天我们来探讨一下synchronized方式。

.1)synchronized方法

       被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象。

public class SyncTest {

	public void print(Thread thread) {
		for (int i = 0; i < 5; i++) {
			System.out.println(Thread.currentThread().getName() + ":" + i);
		}
	}

	class SyncThread extends Thread {

		@Override
		public void run() {
			print(Thread.currentThread());
		}

	}

	public static void main(String[] args) {
		SyncTest test = new SyncTest();
		SyncThread thread1 = test.new SyncThread();
		SyncThread thread2 = test.new SyncThread();
		thread1.start();
		thread2.start();
	}

}
结果:

Thread-0:0
Thread-1:0
Thread-0:1
Thread-1:1
Thread-0:2
Thread-1:2
Thread-0:3
Thread-1:3
Thread-0:4
Thread-1:4
我们在方法print 上加上synchronized 

	public synchronized void print(Thread thread) {
		for (int i = 0; i < 5; i++) {
			System.out.println(Thread.currentThread().getName() + ":" + i);
		}
	}
结果集:

Thread-0:0
Thread-0:1
Thread-0:2
Thread-0:3
Thread-0:4
Thread-1:0
Thread-1:1
Thread-1:2
Thread-1:3
Thread-1:4
说明 Thread-1 在 Thread-0执行完之后方开始执行。

现在我们将测试方法修改一下:

public static void main(String[] args) {
		SyncThread thread1 = new SyncTest().new SyncThread();
		SyncThread thread2 = new SyncTest().new SyncThread();
		thread1.start();
		thread2.start();
	}
我们会发现结果集如下:

Thread-1:0
Thread-0:0
Thread-1:1
Thread-0:1
Thread-1:2
Thread-0:2
Thread-1:3
Thread-0:3
Thread-0:4
Thread-1:4
为什么方法已经synchronized了,却没有我们预期的结果呢,这是因为synchronized只锁定对象(而非代码),每个对象只有一个锁(lock)与之相关联,上面的测试用例中产生了两个SyncTest对象,代码可以这样理解:
	public static void main(String[] args) {
		SyncTest t1=new SyncTest();
		SyncTest t2=new SyncTest();
		SyncThread thread1 = t1.new SyncThread();
		SyncThread thread2 = t2.new SyncThread();
		thread1.start();
		thread2.start();
	}
thread1访问的是t1的synchronized print方法,thread2访问的是t2的synchronized print方法,synchronized锁定的分别是t1.t2,这两把锁是互不干扰的。

synchronized也可以修饰静态方法

      其作用的范围是整个静态方法,作用的对象是这个类的所有对象

在上面的例子中,如果我们将print方法添加修饰符static方法,如下:

public synchronized static void print(Thread thread) {
		for (int i = 0; i < 5; i++) {
			System.out.println(Thread.currentThread().getName() + ":" + i);
		}
	}
就会达到我们预期的效果,原因是静态方法是属于类的而不属于对象的。同样的,synchronized修饰的静态方法锁定的是这个类的所有对象,虽然t1跟t2是不同对象,但是synchronized对这两个对象都起作用。
.2)synchronized 代码块

被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象

synchronized的形式如下:

synchronized(synObject) {
         
}
当在某个线程中执行这段代码块,该线程会获取对象synObject的锁,从而使得其他线程无法同时访问该代码块。

synObject可以是this,代表获取当前对象的锁,也可以是类中的一个属性,代表获取该属性的锁。

我们的代码可以调整为:
public  void print(Thread thread) {
		synchronized(this){
			for (int i = 0; i < 5; i++) {
				System.out.println(Thread.currentThread().getName() + ":" + i);
			}
		}
	}
关于synchronized方法,以下几点需要注意:

(1)当一个线程正在访问一个对象的synchronized方法,那么其他线程能访问该对象的非synchronized方法。

(2)同步加锁的是对象,而不是代码。

(3)实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。


参考资料:
       http://www.cnblogs.com/dolphin0520/p/3923737.html
       http://blog.csdn.net/luoweifu/article/details/46613015




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值