同步互斥访问 - synchronized关键字

单线程中不会出现线程安全问题,而在多线程编程中,有可能会出现同时访问同一个资源的情况。
由于每个线程执行的过程是不可控的,所以很可能导致最终的结果与实际上的愿望相违背或者直接导致程序出错。

线程安全问题,即多个线程同时访问一个资源时,会导致程序运行结果并不是想看到的结果。

那么一般来说,是如何解决线程安全问题的呢?
基本上所有的并发模式在解决线程安全问题时,都采用“序列化访问临界资源”的方案,即在同一时刻,只能有一个线程访问临界资源,也称作同步互斥访问。

在Java中,提供了两种方式来实现同步互斥访问:synchronized和Lock

在Java中,每一个对象都拥有一个锁标记(monitor),也称为监视器,多线程同时访问某个对象时,线程只有获取了该对象的锁才能访问。

在Java中,可以使用synchronized关键字来标记一个方法或者代码块,当某个线程调用该对象的synchronized方法或者访问 synchronized代码块时,这个线程便获得了该对象的锁,其他线程暂时无法访问这个方法,只有等待这个方法执行完毕或者代码块执行完毕,这个线程 才会释放该对象的锁,其他线程才能执行这个方法或者代码块。

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

如果一个线程A需要访问对象object1的synchronized方法fun1,另外一个线程B需要访问对象object2的 synchronized方法fun1,即使object1和object2是同一类型),也不会产生线程安全问题,因为他们访问的是不同的对象,所以不 存在互斥问题。

synchronized代码块类似于以下这种形式
synchronized(synObject) {

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

另外,每个类也会有一个锁,它可以用来控制对static数据成员的并发访问。
并且如果一个线程执行一个对象的非static synchronized方法,另外一个线程需要执行这个对象所属类的static synchronized方法,此时不会发生互斥现象,因为访问static synchronized方法占用的是类锁,而访问非static synchronized方法占用的是对象锁,所以不存在互斥现象。

有一点要注意:对于synchronized方法或者synchronized代码块,当出现异常时,JVM会自动释放当前线程占用的锁,因此不会由于异常导致出现死锁现象。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章