1.2 java線程間的共享與協作

java線程中斷機制

一、java線程的工作方式

java線程之間的工作方式是協作式的,需要自己手動去結束線程,獲取中斷標誌位,進而進行處理,或者判斷當前中斷標誌位是否是true,false就繼續執行自己的業務代碼,不是就直接跳出結束線程。

二、線程中斷的方式

1、在主線程中調用threadObject.interrupt()方法。
2、在子線程中調用isinterrupt()來判斷當前線程是否被中斷了。

三、注意事項

如果方法拋出了interruptException則會將中斷標誌物位重製位flase。需要我們在catch中重新將標誌爲置爲true;

四、Java線程的各種狀態以及切換的方式

在這裏插入圖片描述

五、深入理解run方法和start方法

package cn.enjoy.controller.thread;

/**
 * @author:wangle
 * @description:啓動線程
 * @version:V1.0
 * @date:2020-01-17 11:31
 **/
public class StartThread {


    public static class ThreadRun extends Thread{
        @Override
        public void run(){
            System.out.println("I'm am "+Thread.currentThread().getName());
        }
    }


    public static void main(String arg[]){
        ThreadRun threadRun = new ThreadRun();
        threadRun.setName("ThreadRun");
        threadRun.run();
    }

}

輸出結果:
在這裏插入圖輸出結果片描述
闡述:可以看到,輸出的是main,所以當前執行代碼塊的是主線程。這是java一個面向對象的基本概念,誰調用當前代碼塊就是哪個線程在執行,可以明顯看到是主線程調用了run方法,所以run方法被的當作了一個普通的方法

當使用start啓動線程的時候,jvm纔會給當前線程分配線程資源,真正的啓動一個線程。

六、線程優先級

優先級爲1~10,依次遞減、缺省爲5
使用setPriority方法進行優先級的設定,但是不同虛擬機會進行不同的處理,甚至會忽略掉設置的優先級值。所以不能在程序中太依靠當前值來控制線程優先級。

七、守護線程

threadRun.setDaemon();將線程設置爲守護線程
特點:和主線程生命週期相同
finally的代碼塊不一定會執行,所以在守護線程中不能在finally中進行釋放某些特定資源。以免資源泄漏

八、線程安全

synchronized對臨界資源進行同步

1、作用於實例方法(對象鎖)

a、多個線程訪問同一個對象的同一個方法

public class StartThread implements Runnable {
    //共享資源
    static int i =0;
    /**
     * synchronized 修飾實例方法
     */
    public synchronized void increase(){
        i++;
    }
    @Override
    public void run(){
        for (int j =0 ; j<10000;j++){
            increase();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        StartThread test = new StartThread();
        Thread t1 = new Thread(test);
        Thread t2 = new Thread(test);
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(i);
    }
}

在這裏插入圖片描述
分析:當兩個線程同時對一個對象的一個方法進行操作,只有一個線程能夠搶到鎖。因爲一個對象只有一把鎖,一個線程獲取了該對象的鎖之後,其他線程無法獲取該對象的鎖,就不能訪問該對象的其他synchronized實例方法,但是可以訪問非synchronized修飾的方法

b、一個線程獲取對象鎖之後其他線程來訪問改對象的其他synchronized方法

public class StartThread{



    public synchronized void method1() {
        System.out.println("Method 1 start");
        try {
            System.out.println("Method 1 execute");
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Method 1 end");
    }

    public synchronized void method2() {
        System.out.println("Method 2 start");
        try {
            System.out.println("Method 2 execute");
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Method 2 end");
    }


    public static void main(String[] args) {
        final StartThread test = new StartThread();

        new Thread(new Runnable() {
            @Override
            public void run() {
                test.method1();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                test.method2();
            }
        }).start();
    }
}

在這裏插入圖片描述
分析:一個對象只有一把鎖,當線程1獲取鎖之後,其他線程需要等待1釋放鎖之後才能獲取鎖再去執行其他被同步的方法。

c、線程1獲取鎖之後,其他線程來訪問該對象的非synchronized方法。

分析:在次不再張貼代碼,只需將b中方法2去掉synchronized關鍵字即可。其他線程可以正常訪問非synchronized的方法不需要等待1釋放鎖

d、當多個線程作用於不同的對象的synchronized方法

結果同c、因爲鎖的粒度是在對象的粒度上,非同一個對象使用的不是同一把鎖。

2、synchronized作用於靜態方法(類鎖)

public class StartThread implements Runnable {
    //共享資源
    static int i =0;
    /**
     * synchronized 修飾實例方法
     */
    public static synchronized void increase(){
        i++;
    }
    @Override
    public void run(){
        for (int j =0 ; j<10000;j++){
            increase();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new StartThread());
        Thread t2 = new Thread(new StartThread());
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(i);
    }
}

在這裏插入圖片描述
分析:雖然是不同的線程訪問不同的對象的synchronized方法,但是由於被static方法修飾的方法是屬於類本身的,所以也是被同步了。這就是類鎖

3、synchronized作用於同步代碼

public class synchronizedTest implements Runnable {
    static synchronizedTest instance=new synchronizedTest();
    static int i=0;
    @Override
    public void run() {
        //省略其他耗時操作....
        //使用同步代碼塊對變量i進行同步操作,鎖對象爲instance
        synchronized(instance){
            for(int j=0;j<10000;j++){
                i++;
            }
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Thread t1=new Thread(instance);
        Thread t2=new Thread(instance);
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(i);
    }
}

必須獲取到instance對象的鎖才能執行代碼區域的代碼,所以給過也是被同步的。

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