synchronized总结
2017-06-25 本文已影响71人
一只好奇的茂
synchronized是Java中的关键字,是一种同步锁。
修饰一个代码块或方法
其作用的范围是大括号{}括起来的代码或者整个方法,调用者可获得可获取对象级锁;
修饰一个代码块
public synchronized void method() {
synchronized (this) {
/*** 代码块 ***/
}
}
修饰一个方法
public synchronized void method()
{
// todo
}
以下说明中,代码块同等于方法。
- 当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
- 当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
- 尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。即每个对象只有一个锁(lock)与之相关联,谁拿到这个锁谁就可以运行它所控制的那段代码。
- 在定义接口方法时不能使用synchronized关键字;
- 构造方法不能使用synchronized关键字,但可以使用synchronized代码块来进行同步。
- synchronized 关键字不能被继承 。如果子类覆盖了父类的 被 synchronized 关键字修饰的方法,那么子类的该方法只要没有 synchronized 关键字,那么就默认没有同步,也就是说,不能继承父类的 synchronized。
修饰一个对象
其作用范围是整个对象,调用者可获得可获取对象级锁,当一个线程访问obj对象时,其他试图访问obj对象的线程将会阻塞,直到该线程访问obj对象结束。
public void function(SomeObject obj)
{
//obj 锁定的对象
synchronized(obj)
{
// todo
}
}
修饰一个静态的方法
其作用的范围是整个静态方法,调用者可获得可获取类级锁,即作用的对象是这个类的所有对象;
public synchronized static void method() {
// todo
}
修饰一个类
其作用的范围是synchronized后面括号括起来的部分,调用者可获得可获取类级锁。
class ClassName {
public void method() {
synchronized(ClassName.class) {
// todo
}
}
}
这里就使用同步机制获取互斥锁的情况,进行几点说明:
- 如果同一个方法内同时有两个或更多线程,则每个线程有自己的局部变量拷贝。
- 类的每个实例都有自己的对象级别锁。
- 访问同一个类的不同实例对象中的同步代码块,不存在阻塞等待获取对象锁的问题,因为它们获取的是各自实例的对象级别锁,相互之间没有影响。
- 互斥是实现同步的一种手段,临界区、互斥量和信号量都是主要的互斥实现方式。synchronized关键字经过编译后,会在同步块的前后分别形成monitorenter和monitorexit这两个字节码指令。根据虚拟机规范的要求,在执行monitorenter指令时,首先要尝试获取对象的锁,如果获得了锁,把锁的计数器加1,相应地,在执行monitorexit指令时会将锁计数器减1,当计数器为0时,锁便被释放了。由于synchronized同步块对同一个线程是可重入的,因此一个线程可以多次获得同一个对象的互斥锁,同样,要释放相应次数的该互斥锁,才能最终释放掉该锁。
- 无论synchronized关键字加在方法上还是对象上,如果它作用的对象是非静态的,则它取得的锁是对象;如果synchronized作用的对象是一个静态方法或一个类,则它取得的锁是对类,该类所有的对象同一把锁。
- 实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。
参考
Java中Synchronized的用法
synchronized
Java 多线程:synchronized 关键字用法(修饰类,方法,静态方法,代码块)