shadowplay要下载java_Java并发程序设计(二)Java并行程序基础
Java并行程序基礎
一、線程的生命周期
其中blocked和waiting的區別:
作者:趙老師
鏈接:https://www.zhihu.com/question/27654579/answer/128050125
來源:知乎
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
假設t1,t2先后兩個線程,都執行如下代碼:
synchronized(Obj) {
Obj.wait();
}
t1先進,最后在Obj.wait()下卡住,這時java管t1的狀態waitting狀態
t2后進,直接在第一行就卡住了,這時java叫t2為blocked狀態。
請注意,blocked是過去分詞,意味著他是被卡住的(無辜啊,全是淚)。因為這段代碼只讓一條線程運行。同時,jvm是知道怎么結束blocked的,只要別的線程退出這段代碼,他就會自動讓你進去。也就是說別的線程無需喚醒你,由jvm自動來干。
而waiiting是說我調用wait()等函數,主動卡住自己(我在等一個白富美),請jvm在滿足某種條件后(白富美發消息讓我們晚上見),比如另條線程調用了notify()后,把我喚醒。這個喚醒的責任在于別的線程(白富美)明確的調用一些喚醒函數。
做這樣的區分,是jvm出于管理的需要,做了這種區分,比如兩個原因的線程放兩個隊列里管理,如果別的線程運行出了synchronized這段代碼,我只需要去blocked隊列,放個出來。而某人調用了notify(),我只需要去waitting隊列里取個出來。
P.S. 從linux內核來看,這些線程都是等待狀態,沒區別,區別只在于java的管理需要。通常我們在系統級別說線程的blocked,是說線程操作io,被暫停了,這種線程由linux內核來喚醒(io設備報告數據來了,內核把block的線程放進可運行的進程隊列,依次得到處理器時間),而wait是說,等待一個內核mutex對象,另個線程signal這個mutex后,這個線程才可以運行。區別在于由誰喚醒,是操作系統,還是另一個線程,這里倒和java很相似。
二、線程的基本操作
一)新建線程
1.方法一:
Thread t=newThread();
t.start();//新建一個線程,并在該線程中調用t的run()方法。
2.方法二:
public Class MyThread implementsRunnable{public static voidmian(String[] args){
Thread t2=new Thread(newMyThread());
t2.start();
}
@Overridepublic voidrun(){
System.out.println("I am runnable man!");
}
}
二)終止線程
1.Thread中的stop()方法會直接終止線程,容易引發線程安全問題已經被棄用。
2.所以我們采用不立即中斷線程,而是給目標線程發送通知:“希望你能中斷線程的時候中斷啦!”。而什么時候中斷取決于線程自身。
public void Thread.inerrupt(); //通知線程中斷,設置中斷標志位。
public boolean Thread.isInterrupted() //判斷線程是否有中斷標志位。
public static boolean Thead.interrupted() //判斷線程是否有中斷標志位,如果有則清除標志位。
public static native void sleep(long millis) throws InterruptedException //如果當前線程被設置了中斷標志位,調用sleep方法時,
//就會拋出InterruptedException異常,該異常必須被捕獲。
三)wait和notify
兩個方法都是Object類中的方法,方法簽名為:
public final void wait() throws InterruptException;//線程停止執行轉為等待狀態,直到其他線程調用了同一實例對象的notify()或notifyAll()方法。
public final native void notify();//隨機選擇一個線程,將其喚醒。
需要強調的是,這兩個方法都不能隨便調用,它們必須包含在synchronized語句中。
例如:
public classSimpleWN {final static Object obj=newObject();public static class T1 extendsThread{
@Overridepublic voidrun(){synchronized(obj){
System.out.println(System.currentTimeMillis()+" :T1 start!");try{
System.out.println(System.currentTimeMillis()+" :wait for object!");
obj.wait();
}catch(Exception e){
e.printStackTrace();
}
System.out.println(System.currentTimeMillis()+" :T1 END!");
}
}
}public static class T2 extendsThread{
@Overridepublic voidrun(){synchronized(obj){
System.out.println(System.currentTimeMillis()+" :T2 start! notify one!");
System.out.println(System.currentTimeMillis()+" :wait for object!");
obj.notify();
System.out.println(System.currentTimeMillis()+" :T2 END!");try{
Thread.sleep(3000);
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}public static voidmain(String[] args){
Thread t1=newT1();
Thread t2=newT2();
t1.start();
t2.start();
}
}
四)suspend和resume
– suspend()不會釋放鎖
– 如果加鎖發生在resume()之前 ,則死鎖發生
五)等待線程結束(join)和謙讓(yield)
public final void join() throws InterrupteException //一直阻塞當前線程直到目標線(調用此方法的線程)程執行完畢
public final synchronized void join(long millis) throws InterruptException //超出最大時間會繼續執行。
join線程的本質是讓調用線程wait()在當前線程對象實例上。因此不要在Thread對象實例上使用wait或者notify等類似的方法,因為這很可能影響系統API的工作。
public static native void yield() //使當前線程讓出CPU,與其他線程參與到CPU資源競爭中。
三、守護線程(Deamon)
在后臺默默地完成一些系統性的服務,比如垃圾回收線程、 JIT線程就可以理解為守護線程
當一個Java應用內,只有守護線程時,Java虛擬機就會自然退出。
設置為守護線程:
Thread t=newDaemonT();
t.setDaemon(true);
t.start();
四、實現線程同步的基本方法
關鍵字synchronized的作用是實現線程間的同步,它的工作是對同步的代碼加鎖,使得每一次只能有一個線程進入同步塊。用法:
1)對某個實例對象加鎖。
2)對對象的實例方法加鎖,相當于對當前實例加鎖。
3)對某個類的靜態方法加鎖,相當于對當前類加鎖。
public class MyRunnable implementsRunnable{static MyRunnable instance=newMyRunnable();static Object object=newObject();static int i=0;
@Overridepublic voidrun() {for(int j=0;j<1000;j++){synchronized(object) {
i++;
}
}
}public static void main(String[] args) throwsInterruptedException{
Thread t1=newThread(instance);
Thread t2=newThread(instance);
t1.start();
t2.start();
t1.join();
System.out.println(i);//1562
t2.join();
System.out.println(i);//2000
}
}
沒問題:
public class MyRunnable implementsRunnable{static MyRunnable instance=newMyRunnable();static Object object=newObject();static int i=0;public static synchronized voidincrease(){
i++;
}
@Overridepublic voidrun() {for(int j=0;j<1000;j++){
increase();
}
}public static void main(String[] args) throwsInterruptedException{
Thread t1=new Thread(newMyRunnable());
Thread t2=new Thread(newMyRunnable());
t1.start();
t2.start();
t1.join();
System.out.println(i);//1000
t2.join();
System.out.println(i);//2000
}
}
錯誤的同步方式(自行思考原因):
public class MyRunnable implementsRunnable{static MyRunnable instance=newMyRunnable();static Object object=newObject();static int i=0;public synchronized voidincrease(){
i++;
}
@Overridepublic voidrun() {for(int j=0;j<1000;j++){
increase();
}
}public static void main(String[] args) throwsInterruptedException{
Thread t1=new Thread(newMyRunnable());
Thread t2=new Thread(newMyRunnable());
t1.start();
t2.start();
t1.join();
System.out.println(i);//1747
t2.join();
System.out.println(i);//1747
}
}
五、隱蔽的錯誤
一)并發下的ArrayList
public classArrayListTest {static ArrayList list=new ArrayList<>();public static class AddThread implementsRunnable{
@Overridepublic voidrun() {for(int i=0;i<10000;i++){
list.add(i);
}
}
}public static void main(String[] args) throwsInterruptedException{
Thread t1=new Thread(newAddThread());
Thread t2=new Thread(newAddThread());
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(list.size());
}/*結果:Exception in thread "Thread-1" java.lang.ArrayIndexOutOfBoundsException: 10
at java.util.ArrayList.add(Unknown Source)
at com.tang.test.ArrayListTest$AddThread.run(ArrayListTest.java:12)
at java.lang.Thread.run(Unknown Source)
10005*/}
解決辦法:Vector代替ArrayList
二)更詭異的HashMap
解決辦法:ConcurrentHashMap代替HashMap。
三)錯誤的加鎖
public class BadLock implementsRunnable{
static Integer i=0;
static BadLock instance=newBadLock();
@Override
public voidrun() {
for(int j=0;j<10000;j++){
synchronized(i) {
i++;
}
}
}
public static void main(String[] args) throwsInterruptedException{
Thread t1=newThread(instance);
Thread t2=newThread(instance);
t1.start(); t2.start();
t1.join(); t2.join();
System.out.println(i);
}
//結果:12862
}
總結
以上是生活随笔為你收集整理的shadowplay要下载java_Java并发程序设计(二)Java并行程序基础的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java map赋值给model_Map
- 下一篇: Java编写抓取用户信息代码_[代码全屏