并发编程(8)synchronized的用法
2016-03-17 14:14
281 查看
上一篇中我们讨论了线程安全问题,了解了解决线程安全问题的主要两种方式,今天来探讨一下通过同步互斥方式,在java中提供了两种方式来实现同步互斥访问:synchronized和Lock,今天我们来探讨一下synchronized方式。
.1)synchronized方法
被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象。
现在我们将测试方法修改一下:
synchronized也可以修饰静态方法
其作用的范围是整个静态方法,作用的对象是这个类的所有对象
在上面的例子中,如果我们将print方法添加修饰符static方法,如下:
.2)synchronized 代码块
被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象
synchronized的形式如下:
synObject可以是this,代表获取当前对象的锁,也可以是类中的一个属性,代表获取该属性的锁。
我们的代码可以调整为:
(1)当一个线程正在访问一个对象的synchronized方法,那么其他线程能访问该对象的非synchronized方法。
(2)同步加锁的是对象,而不是代码。
(3)实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。
参考资料:
http://www.cnblogs.com/dolphin0520/p/3923737.html
http://blog.csdn.net/luoweifu/article/details/46613015
.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
相关文章推荐
- C#线程间不能调用剪切板的解决方法
- C#线程同步的三类情景分析
- C#获取进程或线程相关信息的方法
- C#停止线程的方法
- C#子线程更新UI控件的方法实例总结
- C#线程队列用法实例分析
- C++使用CriticalSection实现线程同步实例
- 基于C++实现的线程休眠代码
- VB读取线程、句柄及写入内存的API代码实例
- C#网络编程基础之进程和线程详解
- C#通过Semaphore类控制线程队列的方法
- C#多线程处理多个队列数据的方法
- C#实现线程安全的简易日志记录方法
- C#中线程同步对象的方法分析
- ASP.NET线程相关配置
- 浅析linux环境下一个进程最多能有多少个线程
- 再谈JavaScript线程
- C#实现终止正在执行的线程
- Java线程编程中的主线程讲解
- 解析Java线程同步锁的选择方法