java中实现同步的两种方式:syschronized和lock的区别和联系
轉載自?http://www.cnblogs.com/xiohao/p/4151408.html
? Lock是java.util.concurrent.locks包下的接口,Lock?實現提供了比使用synchronized?方法和語句可獲得的更廣泛的鎖定操作,它能以更優雅的方式處理線程同步問題,我們拿Java線程(二)中的一個例子簡單的實現一下和sychronized一樣的效果,代碼如下:
?
[java]?view plaincopy
?
? ? ? ? 這樣就實現了和sychronized一樣的同步效果,需要注意的是,用sychronized修飾的方法或者語句塊在代碼執行完之后鎖自動釋放,而用Lock需要我們手動釋放鎖,所以為了保證鎖最終被釋放(發生異常情況),要把互斥區放在try內,釋放鎖放在finally內。
?
? ? ? ? 如果說這就是Lock,那么它不能成為同步問題更完美的處理方式,下面要介紹的是讀寫鎖(ReadWriteLock),我們會有一種需求,在對數據進行讀寫的時候,為了保證數據的一致性和完整性,需要讀和寫是互斥的,寫和寫是互斥的,但是讀和讀是不需要互斥的,這樣讀和讀不互斥性能更高些,來看一下不考慮互斥情況的代碼原型:
?
[java]?view plaincopy
?
? ? ? ? 部分輸出結果:
?
?
[java]?view plaincopy
?
? ? ? ? 我們要實現寫入和寫入互斥,讀取和寫入互斥,讀取和讀取互斥,在set和get方法加入sychronized修飾符:
?
?
[java]?view plaincopy
?
? ? ? ? 部分輸出結果:
[java]?view plaincopy
?
? ? ? ? 我們發現,雖然寫入和寫入互斥了,讀取和寫入也互斥了,但是讀取和讀取之間也互斥了,不能并發執行,效率較低,用讀寫鎖實現代碼如下:
?
?
[java]?view plaincopy
?
?
? ? ? ? 部分輸出結果:
?
[java]?view plaincopy
?
? ? ? ? 從結果可以看出實現了我們的需求,這只是鎖的基本用法,鎖的機制還需要繼續深入學習。
? ? ? ? 本文來自:高爽|Coder,原文地址:http://blog.csdn.net/ghsau/article/details/7461369,轉載請注明。
?
?
?
?
在java中有兩種方式實現原子性操作(即同步操作):
1)使用同步關鍵字synchronized
2)使用lock鎖機制其中也包括相應的讀寫鎖
package com.xiaohao.test;
import java.util.Random;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class Test {
public static void main(String[] args) {
final LockTest lock=new LockTest();?
//輸出張三?
new Thread(){
public void run(){
lock.test("張三張三張三張三張三張三張三張三張三張三");
}?
}.start();
//輸出李四
new Thread(){
public void run(){
lock.test("李四李四李四李四李四李四李四李四李四李四");System.out.println?
("\n---------------------------------------------------------------");
}
}.start();
//---------------------------------------------------------------
//模擬寫入數據的
for (int i = 0; i < 3; i++) {?
new Thread(){?
public void run() {?
for (int j = 0; j < 5; j++) {?
// lock.set(new Random().nextInt(30));?
lock.set2(new Random().nextInt(30));
}?
}?
}.start();
}
//模擬讀取數據的
for (int i = 0; i < 3; i++) {?
new Thread(){?
public void run() {?
for (int j = 0; j < 5; j++) {?
// lock.get();?
lock.get2();?
}?
}?
}.start();
}
}
}
class LockTest{
private Lock lock=new ReentrantLock(); //創建普通的鎖
private ReadWriteLock readWriteLock=new ReentrantReadWriteLock();//創建讀寫鎖
private int data;// 共享數據?
//實現同步的方法一 使用同步關鍵字 synchronized
public synchronized void test(String name){
//下面的相關操作是一個原子性的操作
// lock.lock();// 得到鎖?
try {?
for(int i = 0; i < name.length(); i++) {?
System.out.print(name.charAt(i));?
}?
} finally {?
// lock.unlock();// 釋放鎖?
}?
}
//實現同步的方法二 使用lock鎖機制
public void test2(String name){
//下面的相關操作是一個原子性的操作
lock.lock();// 得到鎖?
try {?
for(int i = 0; i < name.length(); i++) {?
System.out.print(name.charAt(i));?
}?
} finally {?
lock.unlock();// 釋放鎖?
}?
}
//使用set方法模擬寫入數據?
//使用 synchronized 實現了讀讀,寫寫,讀寫之間的互斥 ,但讀讀之間的互斥是沒有什么必要的
public synchronized void set(int data){
System.out.println(Thread.currentThread().getName() + "準備寫入數據");?
try {?
Thread.sleep(20);?
} catch (InterruptedException e) {?
e.printStackTrace();?
}?
this.data = data;?
System.out.println(Thread.currentThread().getName() + "寫入" + this.data);?
}
//使用get方法模擬讀取數據
//使用 synchronized 實現了讀讀,寫寫,讀寫之間的互斥 ,但讀讀之間的互斥是沒有什么必要的
public synchronized void get() {?
System.out.println(Thread.currentThread().getName() + "準備讀取數據");?
try {?
Thread.sleep(20);?
} catch (InterruptedException e) {?
e.printStackTrace();?
}?
System.out.println(Thread.currentThread().getName() + "讀取" + this.data);?
}?
//使用set方法模擬寫入數據?
//使用 讀寫鎖實現了寫寫,讀寫之間的互斥 ,但讀讀之間的互斥是沒有什么必要的
public void set2(int data){
readWriteLock.writeLock().lock();//獲取寫入鎖
try{
System.out.println(Thread.currentThread().getName() + "準備寫入數據");?
try {?
Thread.sleep(20);?
} catch (InterruptedException e) {?
e.printStackTrace();?
}?
this.data = data;?
System.out.println(Thread.currentThread().getName() + "寫入" + this.data);?
}
finally{
readWriteLock.writeLock().unlock();
}
}
//使用get方法模擬讀取數據
//使用 讀寫鎖實現了寫寫,讀寫之間的互斥 ,但讀讀之間的互斥是沒有什么必要的
public void get2() {?
//獲取相應的讀鎖
readWriteLock.readLock().lock();
try{
System.out.println(Thread.currentThread().getName() + "準備讀取數據");?
try {?
Thread.sleep(20);?
} catch (InterruptedException e) {?
e.printStackTrace();?
}?
System.out.println(Thread.currentThread().getName() + "讀取" + this.data);?
}
finally{
// 釋放相應的寫鎖
readWriteLock.readLock().unlock();
}
}?
}
?
?
?
線程同步經典版:
package com.xiaohao.test;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class Test2{
?public static void main(String[] args){
??final LockTest2 lockTest=new LockTest2(); ?
?for(int i=0;i<3;i++) ??{ ???
new Thread(){ ???????
? public void run(){?????? ??
??????? try { ?
?? ????? for (int j = 0; j < 3; j++) {? ???
??????? ?lockTest.setValue(); ???
????? } ???} catch (InterruptedException e) { ?
???// TODO Auto-generated catch block ????e.printStackTrace(); ?
??} ??????
? ? } ?????
??? }.start(); ?
?} ?
?for(int i=0;i<3;i++) ??{ ?
??????? new Thread(){ ????
??? ? public void run(){?????? ?? ??? ??
?? try { ??? ????
? for (int j = 0; j < 3; j++) {?
????lockTest.getValue(); ??? ??
??? } ???
} catch (InterruptedException e)
{ ????// TODO Auto-generated catch block ????e.printStackTrace(); ???} ??????
? ? } ??????
?? }.start(); ?
}????
?} ?
}
class? LockTest2 {
?int data=0; ?
ReentrantReadWriteLock lock= new ReentrantReadWriteLock();// 鎖對象
? ?public void setValue() throws InterruptedException{ ??
lock.writeLock().lock(); ?
?System.out.println("正在使用寫鎖......"); ???
data=(int) (Math.random()*10); ??
?System.out.println("正在寫入:"+data); ??
?Thread.sleep(500); ?
?System.out.println("寫鎖調用完畢---------------------------");
??lock.writeLock().unlock(); ?} ?
?public void getValue() throws InterruptedException{
??lock.readLock().lock(); ????
System.out.println("正在使用讀鎖...........................................");
???System.out.println("正在讀入:"+data); ???Thread.sleep(500);
??System.out.println("讀鎖調用完畢......");
??lock.readLock().unlock(); ?
}
}
?
?**** 當一個線程進入了一個對象是的synchronized方法,那么其它線程還能掉否調用此對象的其它方法?
????????這個問題需要分幾種情況進行討論。
????? 1)查看其它方法是否使用了同步關鍵字(synchronized)修飾,如果沒有的話就可以調用相關的方法。
????? 2)在當前synchronized方法中是否調用了wait方法,如果調用了,則對應的鎖已經釋放,可以訪問了。
????? 3)如果其它方法也使用synchronized修飾,并且當前同步方法中沒有調用wait方法的話,這樣是不允許訪問的。
????? 4)如果其它方法是靜態方法的話,由于靜態方法和對象是扯不上什么關系,對于靜態同步方法而言,其對應的同步監視器為當前類的字節碼
?????????? 所以肯定可以訪問的了。
總結
以上是生活随笔為你收集整理的java中实现同步的两种方式:syschronized和lock的区别和联系的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql时间与字符串相互转换
- 下一篇: mybatis 缓存总结以及遇到的问题