您的位置:首页 > 编程语言

并发编程(8)synchronized的用法

2016-03-17 14:14 281 查看
       上一篇中我们讨论了线程安全问题,了解了解决线程安全问题的主要两种方式,今天来探讨一下通过同步互斥方式,在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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  线程