在單執行緒程式中,每次只能做一件事情,後面的事情也需要等待前面的事情完成後才可以進行,如果使用多執行緒程式,雖然能夠實現多處理,但是會發生兩個或以上的執行緒搶占資源的問題,在這個時候就要引進執行緒安全了。
先看個例子:
public class test1 implements runnablecatch(interruptedexception e)
} }public static void main(string args)
}
結果:
thread-0====0
thread-1====0
thread-0====1
thread-1====2
thread-0====4
thread-1====6
thread-0====9
thread-1====12
thread-0====16
thread-1====20
但是如果我們把num放進run()方法中就會發現:
public void run()catch(interruptedexception e)
}}
結果:
thread-0====0
thread-1====0
thread-0====1
thread-1====1
thread-0====3
thread-1====3
thread-0====6
thread-1====6
thread-0====10
thread-1====10
num放進run方法中,就是run方法中的區域性變數,每個執行緒都有這麼乙個區域性變數,每個執行緒都用自己的num,而不是兩個執行緒共用這麼乙個num,所以每個執行緒從0加到4結果都是10。
如何解決資源共享的問題,基本上多有解決多執行緒資源衝突問題的方法都是在指定時間段內只允許乙個執行緒訪問共享資源,這時就需要給共享資源上一道鎖,當訪問完畢就釋放該鎖,讓別的程序來使用該資源。
實現執行緒安全的同步機制有:使用synchronized關鍵字和lock關鍵字。下面我來介紹這2種實現執行緒同步的方式。
1.synchronized:
synchronized可以修飾方法,可以有自己的**塊,也就是修飾物件,synchronized不需要手動釋放鎖,是自動進行的釋放的。還記得我分析過設計模式中的的單例模式,懶漢式的**中就用到了synchronized關鍵字來修飾方法。下面用synchronized關鍵字來解決上例同步問題。
修飾方法:
publicsynchronizedvoid run()catch(interruptedexception e)
}}
也可以加在一般方法上,然後在run()方法中呼叫這個同步方法,說明這時有多個執行緒來訪問這個方法,但是只允許乙個執行緒訪問。
修飾物件:
public void run()catch(interruptedexception e)
} }}
this代表當前物件,如果使用當前物件作為鎖(也可以用其他物件作為鎖),那就說明有很多執行緒需要得到這個物件所,並且執行該物件的方法或者改變該物件的變數。
如果有兩個執行緒試圖進入某個類兩個類不同方法中,並且同步的是同乙個物件鎖,那麼他們任然是互斥的:
public class threadtest1 catch(interruptedexception e)
}} }
public void fun2()catch(interruptedexception e)
}} }
public static void main(string args)
});t1.start();
thread t2 = new thread(new runnable()
});t2.start();
}}
結果:
thread-1:沒有同步在fun2()方法中
thread-1:同步在fun2()方法中
thread-0:沒有同步在fun1()方法中
thread-1:同步在fun2()方法中
thread-1:同步在fun2()方法中
thread-0:同步在fun1()方法中
thread-0:同步在fun1()方法中
thread-0:同步在fun1()方法中
可以看出,在一小段時間內,只有乙個執行緒得到同步鎖,因而只有乙個執行緒在執行,當執行緒1執行完執行緒0才開始執行。
如果兩個方法的同步的不是乙個物件鎖,那會怎樣呢?
private object syncobject = new object();
public void fun1()catch(interruptedexception e)
} }}public void fun2()catch(interruptedexception e)
} }}
結果:
thread-1:沒有同步在fun2()方法中
thread-1:同步在fun2()方法中
thread-0:沒有同步在fun1()方法中
thread-0:同步在fun1()方法中
thread-1:同步在fun2()方法中
thread-0:同步在fun1()方法中
thread-1:同步在fun2()方法中
thread-0:同步在fun1()方法中
fun1()方法中的同步鎖是物件this即當前物件,而fun2()方法中的同步鎖是物件syncobject物件,兩個方法不是用的同乙個物件作為鎖,從執行結果看出執行緒0和執行緒1是交替進行的,說明都得到了各自所需的鎖。
2.lock:
lock是在方法中,當方法需要鎖的時候就lock,當結束的時候就unlock,unlock需要在finally塊中。這裡需要手動呼叫unlock方法釋放鎖。
當用的同一lock鎖:
public class threadtest3 catch(interruptedexception e)
}}finally
} public void fun2()catch(interruptedexception e)
}}finally
} public static void main(string args)
});t1.start();
thread t2 = new thread(new runnable()
});t2.start();
}}
結果:
thread-0:沒有同步到fun1()方法中
thread-0:同步到fun1()方法中
thread-1:沒有同步到fun2()方法中
thread-0:同步到fun1()方法中
thread-0:同步到fun1()方法中
thread-1:同步到fun2()方法中
thread-1:同步到fun2()方法中
thread-1:同步到fun2()方法中
和使用synchronized關鍵字同步乙個物件鎖的情況是一樣的。
再看看使用不一樣的同步鎖:
private lock lock1 = new reentrantlock();
private lock lock2 = new reentrantlock();
public void fun1()catch(interruptedexception e)
} }finally
}public void fun2()catch(interruptedexception e)
} }finally
}
結果:
thread-0:沒有同步到fun1()方法中
thread-1:沒有同步到fun2()方法中
thread-0:同步到fun1()方法中
thread-1:同步到fun2()方法中
thread-1:同步到fun2()方法中
thread-0:同步到fun1()方法中
thread-0:同步到fun1()方法中
thread-1:同步到fun2()方法中
也可以看出結果和使用synchronized關鍵字用不同的同步鎖一樣,執行緒0和執行緒1是交替進行的,也都各自得到所需的鎖。
synchronized和lock都可以實現執行緒的同步,實現資源的共享,每當出現兩個甚至多個可以達到同一目的的方式,我們都會問乙個問題:哪個更好?這個我沒具體測試過,只是在網上搜搜,都是說lock比synchronized好,但是在同步執行緒數量少的時候synchronized效率更高,至於這個臨界點也不是很清楚。還有一點不一樣的就是:如果使用synchronized ,如果a不釋放,b將一直等下去,不能被中斷。如果使用reentrantlock,如果a不釋放,可以使b在等待了足夠長的時間以後,中斷等待,而幹別的事情。
好吧。我們也為多執行緒當一次鎖匠,以後面對多執行緒的同步就不會那麼棘手了。
當Httpclient遇到執行緒池 記一次爬蟲經歷
要抓的資料量有點多,很多個頁面,並且都一樣的處理,那麼直接就上線程池吧.搜了搜,得到了結果,用executors.newfixedthreadpool 來生產出乙個固定大小的執行緒池,後面所有的任務都會被放置在任務佇列中.ok,開始寫 建立執行緒池executorservice executorse...
第一次當專家
以前參加過一次所謂的專家評審的活動,不過是專案建立完以後,評啥先進性的,乙個學術派的老傢伙竟然談開了演算法,真是搞笑。這次鬼使神差的竟然作為專家去評審乙個省裡專案方案,就是說說裡面的道道,和技術基本無關,可以說一群所謂的專家和不負責的開發商進行一場惡搞。這裡面只是簡單介紹一些潛規則,至於有的地方有責...
第一次當CEO
凡事都有頭一遭,比如出任ceo。沒有人生來就會領導人的,尤其是天性散淡的才子佳人。只是經不住功名利祿的引誘,每日動心忍性,一步一步爬到這個位置。突然間發現工作的物件變了,不再有無數的計畫書要寫 無數的客戶要見,而是淹沒在會議與e mail裡。可別小看了這堆mail。表面上彬彬有禮,裡面不知埋著多少圈...