JAVA多線程

多線程概述

多線程是指從軟件或者硬件上實現多個線程併發執行的技術。具備多線程能力的計算機因有硬件支持而可以在同一時間執行多於一個線程,進而提高總體處理性能。java

多線程實現

1.繼承Thread

自定義類繼承Thread類,重寫其中的run()方法(即寫入想讓該線程執行的代碼),在main()函數中建立該類,並調用start()方法就會啓動多線程並執行run()中的代碼多線程

class MyThread extends Thread{
    private String greeting;
    MyThread(String s){
        greeting=s;
    }

    @Override
    public void run() {
        while (true)
        System.out.println(greeting);
    }
}
public class ThreadTest {
    public static void main(String[] args){
        MyThread ms1=new MyThread("haha");
        MyThread ms2=new MyThread("ahah");
        ms1.start();
        ms2.start();
    }
}

2.實現Runnable接口

自定義類實現Runnable接口而且重寫run()方法(即寫入想讓該線程執行的代碼)併發

建立自定義類對象,再以該對象爲參數建立Thread對象,最後使用Thread對象調用start()方法,即多線程完成啓動ide

class MyThread implements Runnable{
    private String greeting;
    MyThread(String s){
        greeting=s;
    }

    @Override
    public void run() {
        while(true)
        System.out.println(greeting);
    }
}
public class ThreadTest {
    public static void main(String[] args){
        MyThread ms1=new MyThread("haha");
        MyThread ms2=new MyThread("ahah");
        new Thread(ms1).start();
        new Thread(ms2).start();
    }
}

兩種方式對比

  1. 繼承Thread
    • 好處:能夠直接使用Thread類中的方法,代碼簡單
    • 弊端:若是已經有了父類,就不能用這種方法
  2. 實現Runnable接口
    • 好處:即便本身定義的線程類有了父類也能夠,由於有了父類也能夠實現接口,並且接口是能夠多實現的
    • 弊端:不能直接使用Thread中的方法須要先獲取到線程對象後,才能獲得Thread的方法,代碼複雜

匿名內部類寫法

  1. 繼承Thread類
public class ThreadTest {
    public static void main(String[] args){
        new Thread(){
            @Override
            public void run() {
                while (true)
                    System.out.println("haha");
            }
        }.start();
    }
}
  1. 實現Runnable接口
public class ThreadTest {
    public static void main(String[] args){
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true)
                    System.out.println("haha");
            }
        }).start();
    }
}

Thread方法

設置和獲取線程名

//構造Thread時設置線程名
Thread(Runnable target, String name) 
//分配一個新的 Thread對象。  
Thread(String name) 
//分配一個新的 Thread對象。  
    
void setName(String name) 
//將此線程的名稱更改成等於參數 name 。     
    
String getName() 
//返回此線程的名稱。

獲取當前線程的對象

static Thread currentThread() 
//返回對當前正在執行的線程對象的引用。

休眠,等待與喚醒線程

static void sleep(long millis) 
//使當前正在執行的線程以指定的毫秒數暫停(暫時中止執行),具體取決於系統定時器和調度程序的精度和準確性。
void wait() 
//致使當前線程等待,直到另外一個線程調用該對象的 notify()方法或 notifyAll()方法。 
void notify() 
//喚醒正在等待對象監視器的單個線程。  
void notifyAll() 
//喚醒正在等待對象監視器的全部線程。

標記守護線程

守護線程又稱後臺線程,服務線程.普通線程在執行結束後中止,而守護線程服務於普通線程,當普通線程都中止守護進程也當即中止(服務對象消失)函數

void setDaemon(boolean on) 
//將此線程標記爲 daemon線程或用戶線程。
class MyThread extends Thread{
    private long last;
    MyThread(long last){//休眠時間
        this.last=last;
    }

    @Override
    public void run() {//休眠last秒而後打印該線程名
        try {
            sleep(last);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(this.getName());
    }
}
public class ThreadTest {
    public static void main(String[] args) throws InterruptedException {
        MyThread ms1=new MyThread(1000);//守護線程持續時間短
        ms1.setName("Daemon thread");
        MyThread ms2=new MyThread(4000);
        ms2.setName("Normal thread");
        ms1.setDaemon(true);
        ms1.start();
        ms2.start();
    }
}
//輸出結果
//Daemon thread
//Normal thread
//若是將main中的代碼改成如下
MyThread ms1=new MyThread(4000);//守護線程持續時間長
ms1.setName("Daemon thread");
MyThread ms2=new MyThread(1000);
ms2.setName("Normal thread");
ms1.setDaemon(true);
ms1.start();
ms2.start();
//輸出結果
//Normal thread
//因爲普通線程早於守護線程中止,守護線程也被迫中止(沒來得及運行)

加入線程

void join() 
//等待這個線程死亡。  
void join(long millis) 
//等待這個線程死亡最多 millis毫秒。
class MyThread extends Thread{
    private long last;
    MyThread(long last){//休眠時間
        this.last=last;
    }

    @Override
    public void run() {//休眠last秒而後打印該線程名
        try {
            sleep(last);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(this.getName());
    }
}
public class ThreadTest {
    public static void main(String[] args) throws InterruptedException {
        MyThread ms1=new MyThread(1000);//守護線程持續時間短
        ms1.setName("first");
        MyThread ms2=new MyThread(4000);
        ms2.setName("second");
        ms2.start();
        ms2.join();//加入線程
        ms1.start();
    }
}
//線程1的睡眠時間短本應線程1先輸出,但因爲線程1執行前調用了線程1的join(),
//該函數會等待線程1中止才繼續下面的代碼
//因此輸出
//second
//first

代碼同步

當須要一段事務代碼須要連續執行而不容許由於多線程的CPU調度在執行過程當中切換線程,這樣就須要代碼同步達到這個要求性能

同步後的代碼不會在執行過程當中發生中斷,也就是說CPU必須一口氣執行完畢this

同步代碼塊

  • 同步代碼塊即便用synchronized關鍵字加上一個鎖對象來定義一段代碼線程

  • 多個同步代碼塊若是使用相同的鎖對象, 那麼他們就是同步的code

    public class ThreadTest {
        public static void main(String[] args){
            Object o=new Object();
            new Thread(){
                @Override
                public void run() {
                    while (true) {
                        synchronized (o) {//鎖對象能夠是任意對象,可是被鎖的代碼須要保證是同一把鎖,不能用匿名對象
                            for (int i = 0; i < 10; i++) {
                                System.out.print(i);
                            }
                            System.out.println();
                        }
                    }
                }
            }.start();
            new Thread(){
                @Override
                public void run() {
                    while (true) {
                        synchronized (o) {
                            for (int i = 0; i < 10; i++) {
                                System.out.print(i);
                            }
                            System.out.println();
                        }
                    }
                }
            }.start();
        }
    }
    //若是不加synchronized那麼打印出來的的不必定每一行都是0123456789

同步方法

  • 靜態方法同步鎖對象是當前類的字節碼對象
  • 非靜態同步方法鎖對象是this
public static synchronized void printNum() {    
    //使用synchronized關鍵字修飾的方法中全部的代碼都是同步的
    for(int i=0;i<10;i++)
        System.out.println();
}

Timer(計時器)

  • 對任務進行定時規劃運行
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class ThreadTest {
    public static void main(String[] args) throws InterruptedException {
        Timer t = new Timer();
        t.schedule(new MyTimerTask(), new Date(),3000);//三秒打印一次O(∩_∩)O
        while(true) {
            System.out.println(new Date());//每秒打印一次時間
            Thread.sleep(1000);
        }
    }
}
class MyTimerTask extends TimerTask {
    @Override
    public void run() {
        System.out.println("O(∩_∩)O");
    }
}
相關文章
相關標籤/搜索