您的位置:首页 > 职场人生

黑马程序员——Java多线程—线程互斥—synchronized

2014-09-28 10:21 155 查看
对象的锁
在Java中,所有对象都自动含有单一的锁,JVM负责跟踪对象被加锁的次数。

在线程第一次给对象加锁的时候,锁的计数变为1;每当这个相同的线程在此对象上再次加锁时,计数会递增,只有首先获得锁的线程才能继续获取该对象上的多个锁。

每当任务离开一个synchronized方法或代码块,计数递减;当计数为0的时候,锁被完全释放,此时别的线程就可以获得此对象的锁,进而访问共享资源。

在Java中synchronized为多线程互斥访问共享资源提供了支持。

synchronized有2种作用域:

1、实例范围:所谓实例范围是指synchronized关键字用在实例方法中。

2、类范围:所谓类范围是指synchronized关键字用在类方法中。

对于每一种作用域都有2种表现形式:

1、synchronized方法

2、synchronized代码块

实例范围+synchronized方法

public class Test{
public synchronized void method1(){
// 需要被互斥访问的代码
}
}

当使用synchronized修饰非静态成员方法时,无需指定要获取哪个对象的锁,系统会默认获取当前对象(即this)的锁。

如果一个类有多个被synchronized修饰的非静态成员方法,只要有一个线程正在访问任意一个非静态synchronized方法,则其它线程不能再访问这个类中任何非静态的synchronized方法。但是,不同的对象实例的synchronized方法是不相干扰的;也就是说,其它线程照样可以同时访问相同类的另一个对象实例中的synchronized方法。

实例范围+synchronized代码块

public class Test{
public void method1(){
// 无需互斥访问的代码
synchronized(obj){
// 需要被互斥访问的代码块
}
}
}

当使用synchronized代码块时,必须显式指定获取锁的对象,这个对象是任意的,可以是当前对象(即this),也可以是类中的成员属性等;但是必须保证当多个线程来获取该对象的锁时,得到的是同一把锁(即上面代码中的obj对多个线程来说是同一个对象),否则该代码块不能被互斥访问。

类范围+synchronized方法

public class Test{

public static synchronized void method1(){
// 需要被互斥访问的代码
}

public synchronized static void method2(){
// 需要被互斥访问的代码
}
}

static 和 synchronized 的先后顺序是任意的。

当使用synchronized修饰类方法时,无需指定要获取哪个对象的锁,系统会默认获取本类的类对象(即Test.class)的锁。

如果一个类中有多个被synchronized修饰的类方法,那么在同一时刻只能有一个线程可以获得Test.class对象的锁,也就只能有一个synchronized类方法运行。

类范围+synchronized代码块

public class Test{

public static void method1(){
// 不需要被互斥访问的代码
synchronized(obj){
// 需要被互斥访问的代码
}
}
}

完全类似于实例范围+synchronized代码块。

注意:

1、synchronized关键字是不能继承的,也就是说,基类的方法synchronized f(){} 在继承类中并不自动是synchronized f(){},而是变成了f(){}。继承类需要你显式的指定它的某个方法为synchronized方法。

2、无论synchronized关键字加在方法上还是代码块上,它取得的锁都是对象,而不是把一段代码或函数当作锁。

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

如果使用synchronized控制线程互斥,则线程会在如下几种情况下释放对监视器的锁定:

1、当前线程的synchronized方法、synchronized代码块执行结束,当前线程即释放监视器。

2、当前线程在synchronized方法、synchronized代码块中遇到break、return终止了该方法、该代码块的继续执行,当前线程会释放监视器。

3、当前线程在synchronized方法、synchronized代码块中出现了未处理的Error或Exception,导致该方法、该代码块异常结束时,当前对象会释放监视器。

4、当前线程执行synchronized方法、synchronized代码块是,执行了监视器对象的wait方法,则当前线程暂停,并释放监视器。

出现如下情况不会释放监视器:

1、线程执行synchronized方法、synchronized代码块时,程序调用了Thread.sleep()、Thread.yield()方法来暂停当前线程的执行,当前线程不会释放监视器。

2、线程执行synchronized方法、synchronized代码块时,其他线程调用了该线程的suspend方法将该线程挂起,该线程不会释放监视器(我们应该尽量避免使用suspend、resume方法来控制线程)。

参考:

CSDN:
【Java线程】锁机制:synchronized、Lock、Condition

CSDN:

Java多线程编程--(3)线程互斥、同步的理解

CSDN 高爽:Java线程(二):线程同步synchronized和volatile

51CTO: Java锁机制Synchronized
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息