多線程(一)(主要關於API)(Java多線程編程核心技術)

最近在讀java多線程編程核心技術,記錄學習心得java

實現多線程有兩種:1.繼承Thread類 2.實現Runnable接口編程

1.1繼承Thread類安全

class Thread implements Runnable (Thread 繼承了Runnable接口)

使用多線程技術時,代碼運行結果與代碼執行順序或調用順序是無關的.多線程

1.2實現Runnable接口(若是已經有父類了,不能在繼承Thread類,則實現Runnable接口)dom

把Thread類對象傳入構造函數,能夠實現將一個Thread對象的run方法交給其餘的線程使用ide

public class CountOperate extends Thread{
    public CountOperate(){
        System.out.println("CountOperate---begin");
        System.out.println("Thread.currentThread().getName="+Thread.currentThread().getName());
        System.out.println("this.getName="+this.getName());
        System.out.println("CountOperate----end");
    }

    @Override
    public void run() {
        System.out.println("run---begin");
        System.out.println("Thread.currentThread().getName="+Thread.currentThread().getName());
        System.out.println("this.getName="+this.getName());
        System.out.println("run----end");
    }
}

第一種:函數

public static void main(String[] args) {
        CountOperate c=new CountOperate();
        Thread t1=new Thread("A");
        t1.start();
        /*output:
            CountOperate---begin
            Thread.currentThread().getName=main
            this.getName=Thread-0
            CountOperate----end
        */
    }

是main線程執行構造函數(ps:這個main和main方法不要緊,只不過名字相同)學習

第二種:測試

public static void main(String[] args) {
        CountOperate c=new CountOperate();
        Thread t1=new Thread(c,"A");
        t1.start();
        /*
         CountOperate---begin
         Thread.currentThread().getName=main
         this.getName=Thread-0
         CountOperate----end
         run---begin
         Thread.currentThread().getName=A
         this.getName=Thread-0
         run----end
        */
    }

main線程執行構造方法,start()會自動調用run方法this

2 實例變量與線程安全

這裏就涉及到一個線程安全的問題了.

public class MyThread extends Thread{
    private int count=5;

    @Override
    public void run() {
        super.run();
        count--;
        System.out.println("由"+Thread.currentThread().getName()+"計算 count="+count);
    }
}
public static void main(String[] args) {
    MyThread myThread=new MyThread();
    Thread a=new Thread(myThread,"a");
    Thread b=new Thread(myThread,"b");
    Thread c=new Thread(myThread,"c");
    Thread d=new Thread(myThread,"d");
    Thread e=new Thread(myThread,"e");
    a.start();
    b.start();
    c.start();
    d.start();
    e.start();
    /*output:
    由a計算 count=2
    由c計算 count=2
    由d計算 count=1
    由b計算 count=2
    由e計算 count=0
     */
}

緣由:i--,分爲3步4, 1)取得原有的i值 2)計算i-1 3)對i進行賦值 同時訪問i值,就會產生非線程安全問題

解決方法:在run方法synchronized 關鍵字

3.Thread currentThread():獲取當前線程對象

boolean siAlive():判斷當前的進程是否處於活動狀態

String getId() 獲取線程的惟一標識

4.線程中斷

interrupt():中止線程

interrupted():判斷當前線程是否已經中斷

isInterrupted():測試線程是否已經中斷

ps:比較interrupted()方法和isInterrupted()方法?

從源碼看:

public static boolean interrupted() {
    return currentThread().isInterrupted(true);
}

舉個例子咱們能更好理解:

//線程類
public class MyThread extends Thread{
    @Override
    public void run() {
        super.run();
        for (int i = 0; i <50000; i++) {
            System.out.println("i="+(i+1));
        }
    }
}
//測試類
public class Run2 {
    public static void main(String[] args) {
        Thread.currentThread().interrupt();
        System.out.println("是否中止1?="+Thread.interrupted());
        System.out.println("是否中止2?="+Thread.interrupted());
    }
    /*output:
        是否中止1?=true
        是否中止2?=false
    */
}

緣由:interrupted()方法具備清除狀態的功能

ps:native修飾方法

public void interrupt() {
    if (this != Thread.currentThread())
        checkAccess();

    synchronized (blockerLock) {
        Interruptible b = blocker;
        if (b != null) {
            interrupt0();           // Just to set the interrupt flag
            b.interrupt(this);
            return;
        }
    }
    interrupt0();
}
private native void interrupt0();

native修飾方法,表示調用的是原生態方法,方法對應的實現不是在當前文件,而是在用其餘語言(如C和C++)實現的文件中.

public boolean isInterrupted() {
    return isInterrupted(false);
}

例子:

public static void main(String[] args) {
    try {
        MyThread myThread=new MyThread();
        myThread.start();
        myThread.sleep(1000);
        myThread.interrupt();
        System.out.println("是否中止1?="+myThread.isInterrupted());
        System.out.println("是否中止2?="+myThread.isInterrupted());
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("end!");
}
/*取打印結果:
是否中止1?=false
是否中止2?=false
end!
*/

isInterrupted()測試線程對象是否已是中斷狀態,但不清除狀態標誌.

5.在沉睡中中止:

public class MyThread extends Thread{
    @Override
    public void run() {
        super.run();
        try {
            System.out.println("run begin");
            System.out.println("線程1="+Thread.currentThread().getName());
            Thread.sleep(200000);
            System.out.println("run end");
        } catch (InterruptedException e) {
            System.out.println("在沉睡中中止!進入catch!");
            e.printStackTrace();
        }
    }
}
public static void main(String[] args) {
        MyThread thread =new MyThread();
        try {
            thread.start();
            System.out.println("線程2="+Thread.currentThread().getName());
            Thread.sleep(2000);
            thread.interrupt();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("end!");
}
/*
output:
線程2=main
run begin
線程1=Thread-0
end!
在沉睡中中止!進入catch!
java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at us.codecraft.tinyioc.MyThread.run(MyThread.java:59)
*/
    }

stop() 包裏中止線程,可是可能會形成數據不一致的結果,不建議使用

使用return 中止線程

while (true) {
    if (Thread.interrupted()) {
        System.out.println("中止了");
        return;
    }
    System.out.println(System.currentTimeMillis());
}

6.暫停線程

suspend()(暫停線程)和resume()(重啓線程)方法

缺點:

(1).獨佔,若是使用不當會,會形成公共的同步對象的獨佔,使其餘線程沒法訪問公共同步對象

(2).不一樣步

7.yield():放棄當前的cpu資源,將他讓給其餘的任務去佔用cpu執行時間,但放棄的時間不肯定,有可能剛剛放棄,立刻又獲取cpu時間片

@Override
public void run() {
    long beginTime=System.currentTimeMillis();
    int count =0;
    for (int i = 0; i <5000000 ; i++) {
        //Thread.yield();
        count=count+(i+1);
    }
    long endTime=System.currentTimeMillis();
    System.out.println("用時:"+(endTime-beginTime)+"毫秒");
}
public static void main(String[] args) {
    MyThread thread=new MyThread();
    thread.start();
/*output:用時:11毫秒*/
//去掉Thread.yield()
/*用時:453毫秒*/
}

8.線程的優先級 setPriority()

public final void setPriority(int newPriority) {
    ThreadGroup g;
    checkAccess();
    //線程優先級分爲1-10,若是小於1大於10 則拋出異常
    if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
        throw new IllegalArgumentException();
    }
    if((g = getThreadGroup()) != null) {
    //若是設置權限登記大於線程組的最大等級,就將設置權限設爲線程租最大等級
        if (newPriority > g.getMaxPriority()) {
            newPriority = g.getMaxPriority();
        }
        setPriority0(priority = newPriority);
    }
}

優先級能夠被繼承(此繼承非彼繼承),好比由A線程啓動B線程,B線程的優先級與A是同樣的

8 優先級具備規則性

public class MyThread1 extends Thread{
    @Override
    public void run() {
       long beginTime=System.currentTimeMillis();
       long addResult=0;
       for(int j = 0; j <10; j++){
            //業務邏輯
           for (int i = 0; i <50000; i++) {
               Random random=new Random();
               random.nextInt();
               addResult=addResult+i;
           }
       }

        long endTime=System.currentTimeMillis();
        System.out.println("***** thread 1 use time ="+(endTime-beginTime));
    }
}
public class MyThread2 extends Thread{
    @Override
    public void run() {
        long beginTime=System.currentTimeMillis();
        long addResult=0;
        for (int i = 0; i <10; i++) {
            //業務邏輯
            for (int j = 0; j <50000; j++) {
                Random random=new Random();
                random.nextInt();
                addResult=addResult+i;
            }
        }
        long endTime=System.currentTimeMillis();
        System.out.println("***** thread 2 use time ="+(endTime-beginTime));
    }
}
public class Run {
    public static void main(String[] args) {
        for (int i = 0; i <5 ; i++) {
            MyThread1 thread1=new MyThread1();
            thread1.setPriority(1);
            thread1.start();
            MyThread2 thread2=new MyThread2();
            thread2.setPriority(10);
            thread2.start();
        }
    }
}

結果:

//***** thread 2 use time =130  ***** thread 2 use time =263    ***** thread 2 use time =279
//***** thread 2 use time =156  ***** thread 2 use time =284    ***** thread 2 use time =328
//***** thread 1 use time =248  ***** thread 1 use time =292    ***** thread 2 use time =364
//***** thread 2 use time =355  ***** thread 1 use time =315    ***** thread 1 use time =393
//***** thread 1 use time =370  ***** thread 1 use time =334    ***** thread 1 use time =351
//***** thread 2 use time =387  ***** thread 1 use time =370    ***** thread 2 use time =433
//***** thread 2 use time =396  ***** thread 2 use time =428    ***** thread 1 use time =437
//***** thread 1 use time =397  ***** thread 2 use time =433    ***** thread 2 use time =440
//***** thread 1 use time =431  ***** thread 1 use time =402    ***** thread 1 use time =440
//***** thread 1 use time =455  ***** thread 2 use time =447    ***** thread 1 use time =443

總結:這是3次執行結果,咱們發現,優先級較高則優先執行完run()方法中的任務,但這個結果不能說的太確定,由於優先級還具備隨機性(第二列),也就是優先級高的線程不必定每一次都先執行完.

也就是說優先級高的獲取cpu資源的機率大,可是有時候機率低的也有可能先執行完.

9守護線程

線程有兩種,第一種是用戶線程,第二種是守護線程(例如垃圾回收器)

若是沒有非守護線程,則守護線程自動銷燬

例子:

public class MyThread extends Thread{
    private int i=0;
    @Override
    public void run() {

        try {
            while (true) {
                i++;
                System.out.println("i=" + i);
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class Run {
    public static void main(String[] args) {
        try {
            MyThread thread=new MyThread();
            //設置爲守護線程
            thread.setDaemon(true);
            thread.start();
            Thread.sleep(5000);
            //主線程沉睡,守護線程離開thread對象再也不打印
            System.out.println("我離開thread對象就再也不打印了");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    /*output:
    i=1
    i=2
    i=3
    i=4
    i=5
    我離開thread對象就再也不打印了
    i=6
    */
}
相關文章
相關標籤/搜索