Java線程

Java線程--基本知識

大部分時候,我們做的是單線程編程,但實際情況是,單線程的程序往往功能有限,這就需要使用多線程。Java中程序運行時就啓動了兩個線程:

1.Main線程:調用main方法,執行main方法。

2.GC線程:在main線程運行時運行,回收程序運行之中的垃圾。

線程就是一條執行路徑。多線程完成多個功能併發併發執行的效果。

那麼如何來寫多線程呢?寫多線程有兩種方式:

1. 繼承自Thread類,重寫run方法。然後用Threadstart方法啓動線程。

2. 實現Runnable接口,實現run方法。然後用Threadstart方法啓動線程。

這兩種方式的區別是:

1. 第一種使用簡單。

2. 第二種不受java單繼承的限制。一般來說,都是用第二種。

多線程執行順序是:多線程之間亂序執行、同一線程內部順序執行。

線程中常用的方法:

線程中的已過時方法禁止使用。其他類中的過時方法不建議使用。

1. start:啓動一個新線程。啓動之後jvm會自動執行run方法。

2. run:線程啓動之後執行的方法。

3. setNamegetName:自動命名,Thread-0,1

4. currentThread:得到當前運行的線程。

5. getPriority()setPriority 得到和設置當前線程的優先級。優先級1-10,如果不指定默認是5. 理論上,誰優先級高,誰被cpu調度的可能性就大。但是優先級低的並不是不執行。資源不足的時候纔有效果。

6. setDaemon:將線程置爲守護線程。只能在線程start之前調用。一般用於爲其他線程提供服務,比如GC。守護線程會隨着其他非守護線程的結束而結束。isDaemon可以用於判斷某個線程是否是守護線程。

7. sleep:讓當前線程停止執行(休眠)一段時間。

8. join:如果在A線程中B線程join進來,則現在執行B的內容,直到B執行完畢才繼續執行A。比如A是顯示數據  B是收集收據。

9. yield:讓位:讓出執行權,和其他線程爭奪資源,誰拿到cpu時間片誰執行。

下面讓我們通過具體例子來分別理解一下多線程中的各個方法:

先看一下寫多線程的第一種方式:

public class TestThread {
    public static void main(String[] args) {
        MyThread mt = new MyThread();
        mt.start();//啓動線程
//      mt.run();// 屬於方法的調用,沒有開新線程。整個就一個main線程。
        for(int i = 0;i<100;i++){
            System.out.println("main-->"+i);
        }
    }
}
class MyThread extends Thread{
    @Override
    public void run() {
        for(int i = 0;i<100;i++){
            System.out.println("run-->"+i);
        }
    }
}
由於執行結果在每臺電腦上是不一樣的,所以大家可以自己驗證一下。

再看一下第二種方式:

public class TestRunable {
    public static void main(String[] args) {
        MyRun mr = new MyRun();
        Thread th = new Thread(mr/*,"新線程"*/);
//      th.setName("新線程");//設置名字
//      Thread.currentThread().setName("主線程");
//      Thread.currentThread()獲得當前正在運行的線程
        th.start();//啓動新線程
//      Thread th1 = new Thread(mr/*,"新線程"*/);
//      th1.start();
        for(int i = 0;i<100;i++){
    System.out.println(Thread.currentThread().getName()+"-->"+i);
        }
    }
}
class MyRun implements Runnable{
    @Override
    public void run() {
        for(int i = 0;i<100;i++){
            //如果不給線程起名字,默認的是Thread-0如果在多一個線程,則爲Thread-1,以此類推
            System.out.println(Thread.currentThread().getName()+"-->"+i);
        }
    }
}
這裏設置名字在實際中是不需要的,我們通常使用默認的,即用Thread.currentThread()這個方法

接下來說一下優先級的問題:

public class TestProirity {
    public static void main(String[] args) {
        Run r = new Run();
        Thread th1 = new Thread(r);
        th1.setPriority(10);//優先級最高是10
        th1.start();
        Thread th2 = new Thread(r);
        th2.setPriority(1);//優先級最低是1
        th2.start();
//      System.out.println(th1.getPriority());//默認線程的優先級是5
    }
}
class Run implements Runnable{
    @Override
    public void run() {
        for(int i = 0;i<10000;i++){
    System.out.println(Thread.currentThread().getName()+"-->"+i);
        }
    }
}
如果執行次數很少的話,優先級的作用不是很明顯,所以這裏執行次數多一些。

接下來是守護線程:

public class TestDaemon {
    public static void main(String[] args) {
        Run1 r = new Run1();
        Thread th1 = new Thread(r);
        th1.setDaemon(true);//設置爲守護線程
        th1.isDaemon();//判斷是否是守護線程
        th1.start();
        for(int i = 0;i<100;i++){
    System.out.println(Thread.currentThread().getName()+"-->"+i);
        }
    }
}
class Run1 implements Runnable{
    @Override
    public void run() {
        while(true){
            System.out.println("我是守護線程");
        }
    }
}
如果不設置爲守護線程,那麼線程會一直執行下去,而設置爲守護線程之後,守護線程就會隨着其他線程的結束。

接下來是睡眠:

public class TestSleep {
    public static void main(String[] args) {
        Run2 r = new Run2();
        Thread th = new Thread(r);
        th.start();
        for(int i = 0;i<100;i++){
            try {
                th.sleep(1000);//睡眠一秒鐘
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"-->"+i);
        }
    }
}
class Run2 implements Runnable{
    @Override
    public void run() {
        for(int i = 0;i<100;i++){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"-->"+i);
        }
    }
}
加入sleep()之後我們會發現執行結果是每一秒顯示一句。

接下來是join

public class TestJoin {
    public static void main(String[] args) {
        MyRun1 mr = new MyRun1();
        Thread th = new Thread(mr);
        th.start();//啓動新線程
        try {
            th.join();// 在main中把th1加進來,th1就先執行,執行完畢後main才能繼續執行
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for(int i = 0;i<100;i++){
            System.out.println(Thread.currentThread().getName()+"-->"+i);
        }
    }
}
class MyRun1 implements Runnable{
    @Override
    public void run() {
        for(int i = 0;i<100;i++){
            System.out.println(Thread.currentThread().getName()+"-->"+i);
        }
    }
}
執行結果是先執行完thread中的然後再執行main中的。

接下來是yield

public class TestYield {
    public static void main(String[] args) {
        MyRun2 mr = new MyRun2();
        Thread th = new Thread(mr);
        th.start();
        for(int i = 0;i<100;i++){
            System.out.println(Thread.currentThread().getName()+"-->"+i);
        }
    }
}
class MyRun2 implements Runnable{
    @Override
    public void run() {
        for(int i = 0;i<100;i++){
            System.out.println("讓你執行");
            Thread.yield();//讓位
            System.out.println(Thread.currentThread().getName()+"-->"+i);
        }
    }
}
執行結果大家可以自己驗證一下,有一點需要注意就是yield只是讓出執行權而並不是不執行了。

線程的東西就先說這麼多吧!剩下的再補充。


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