線程安全問題存在,必然會引起很多問題。那麼本節就來講講,如何解決線程安全問題呢?
1、synchronized
synchronized關鍵字,就是java用來控制線程同步的,比如上節的最後舉例中,在代碼中加入共享變量後,使用多線程調用時,會產生count數據產生偏差問題。
此關鍵字,一般是加在方法上的如:
public static int count =0;
public static void main(String[] args){
for (int i = 0; i <3 ; i++) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(getcountNum(30));
System.out.println("count爲:"+count);
try{
Thread.sleep(1);
}catch (Exception e){
e.printStackTrace();
}
}
}).start();
}
}
public static synchronized int getcountNum(int j){
int i =1;
count++;
j=j+3;
return j;
}
運行結果爲:
此方法就變成了一個線程安全的方法了。
首先synchronized鎖的是括號裏的對象,而不是代碼,其次,對於非靜態的synchronized方法,鎖的是對象本身也就是this。
當synchronized鎖住一個對象之後,別的線程如果想要獲取鎖對象,那麼就必須等這個線程執行完釋放鎖對象之後纔可以,否則一直處於等待狀態。
雖然加synchronized關鍵字,可以讓我們的線程變得安全,但是我們在用的時候,也要注意縮小synchronized的使用範圍,如果隨意使用時很影響程序的性能,別的對象想拿到鎖,結果你沒用鎖還一直把鎖佔用,這樣就有點浪費資源。
也就是說:1.非static方法,同步鎖是this。2.static方法,使用當前方法所在類的字節碼對象(Apple.class)是同步鎖
2、lock
先來說說它跟synchronized有什麼區別吧,Lock是在Java1.6被引入進來的,Lock的引入讓鎖有了可操作性,什麼意思?就是我們在需要的時候去手動的獲取鎖和釋放鎖,甚至我們還可以中斷獲取以及超時獲取的同步特性,但是從使用上說Lock明顯沒有synchronized使用起來方便快捷。我們先來看下一般是如何使用的:
public static void main(String[] args){
for (int i = 0; i <3 ; i++) {
new Thread(new Runnable() {
@Override
public void run() {
getcountNum(Thread.currentThread(),30);
try{
Thread.sleep(1);
}catch (Exception e){
e.printStackTrace();
}
}
}).start();
}
}
private static Lock lock = new ReentrantLock();
public static int getcountNum(Thread a,int j){
lock.lock();
int i =1;
count++;
System.out.println("當前是線程:"+a.getName()+",count="+count);
j=j+3;
lock.unlock();
return j;
}
上次分享線程不安全的文章中,得到的count全是3,加上鎖後得到結果是: