1. 程式人生 > >java 多執行緒 之Thread

java 多執行緒 之Thread

參考部落格

Java多執行緒學習(總結很詳細!!!)

根據java 8關於thread的介紹:

有兩種方法可以建立執行緒

第一種是繼承Thread ,需要重寫Thread的run方法

class PrimeThread extends Thread {
    long minPrime;
    PrimeThread(long minPrime) {
        this.minPrime = minPrime;
    }
 
    public void run() {
        // compute primes larger than minPrime
         . . .
    }
}

 以下程式碼將建立一個執行緒並開始執行

 PrimeThread p = new PrimeThread(143);
 p.start();

 另一個方法是implements Runable 介面

class PrimeRun implements Runnable {
    long minPrime;
    PrimeRun(long minPrime) {
         this.minPrime = minPrime;
    }
 
    public void run() {
        // compute primes larger than minPrime
         . . .
    }
}
 PrimeRun p = new PrimeRun(143);
 new Thread(p).start();

今天就說一下Thread與Runable

public class Thread implements Runnable

//返回當前正在執行的執行緒的引用
public static native Thread currentThread();

//使當前執行緒從執行狀態(執行狀態)變為可執行態(就緒狀態),但還可能會繼續執行當前執行緒
public static native void yield();

//正在執行的執行緒進入休眠狀態(暫時停止執行)
//millis 休眠時間 毫秒 >=0
public static native void sleep(long millis) throws InterruptedException;

//指定毫秒數以及納秒數
public static void sleep(long millis, int nanos)
    throws InterruptedException {
        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (nanos < 0 || nanos > 999999) {
            throw new IllegalArgumentException(
                                "nanosecond timeout value out of range");
        }

        if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
            millis++;
        }

        sleep(millis);
    }
//分配一個新的Thread物件
public Thread() {
        init(null, null, "Thread-" + nextThreadNum(), 0);
    }

//
 public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }

//name 新執行緒的name
public Thread(String name) {
        init(null, null, name, 0);
    }


public class Thread1 extends Thread {
	
	
	@Override
	public void run() {
		for(int i = 0;i < 5;i++) {
			System.out.println(Thread.currentThread().getName()+": "+i);
		}
	}
	
	
}



/**
 * start()方法的呼叫後並不是立即執行多執行緒程式碼,而是使得該執行緒變為可執行態(Runnable),什麼時候執行是由作業系統決定的。
 * @author yifei.Wang
 *
 */
public class Main {

	public static void main(String[] args) {
		Thread1 mTh1 = new Thread1();
		Thread1 mTh2 = new Thread1();
		mTh1.start();
		mTh2.start();
		//mTh2.start(); 重複呼叫會出異常

	}

}
public class Thread1 implements Runnable {
	
	@Override
	public void run() {
		for(int i = 0;i < 5;i++) {
			System.out.println(Thread.currentThread().getName()+": "+i);
		}
	}
	
}

public class Main {

	public static void main(String[] args) {
		Thread1 tq = new Thread1();
		new Thread(tq).start();
		new Thread(tq).start();
	}

}

如果一個類繼承Thread,則不適合資源共享。但是如果實現了Runable介面的話,則很容易的實現資源共享。

因為有多個Thread,那麼就要new 多個 Thread 因為有共享資源,所以資源必須是static修飾的

例如

public class Thread2 extends Thread {
	
	static int m = 10;
	@Override
	public void run() {
		for(int i = 0;i < 5;i++) {
			m--;
			System.out.println(Thread.currentThread().getName()+": "+i+": "+m);
		}
	}
}


public class Main {

	public static void main(String[] args) {
		Thread2 t1 = new Thread2();
		Thread2 t2 = new Thread2();
		Thread2 t3 = new Thread2();
		Thread2 t4 = new Thread2();
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}

}

但是 如果使用Runnable

public class Thread1 implements Runnable {
	
	private int m = 10;
	@Override
	public void run() {
		for(int i = 0;i < 5;i++) {
			m--;
			System.out.println(Thread.currentThread().getName()+": "+i+": "+m);
		}
	}
	
}

public class Main2 {

	public static void main(String[] args) {
		Thread1 thread1 = new Thread1();
		new Thread(thread1).start();
		new Thread(thread1).start();
		new Thread(thread1).start();
		new Thread(thread1).start();
	}

}

則不需要設定 靜態變量了,因為我們一直用一個Thread1  沒有new 多個Thread1 ,也可以說,如果我們new 多個Thread1 ,那麼使用private就不行了

發現 Thread也實現了Runnable介面,Runnable接口裡只有一個run方法

啟動執行緒的時候就會呼叫run方法

public interface Runnable {

    public abstract void run();

}

java中執行緒是有優先順序的

 /**
     * The minimum priority that a thread can have.
     */
    public final static int MIN_PRIORITY = 1;

   /**
     * The default priority that is assigned to a thread.
     */
    public final static int NORM_PRIORITY = 5;

    /**
     * The maximum priority that a thread can have.
     */
    public final static int MAX_PRIORITY = 10;

//設定優先順序
public final void setPriority(int newPriority) {
        ThreadGroup g;
        checkAccess();
        if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
            throw new IllegalArgumentException();
        }
        if((g = getThreadGroup()) != null) {
            if (newPriority > g.getMaxPriority()) {
                newPriority = g.getMaxPriority();
            }
            setPriority0(priority = newPriority);
        }
    }

// 獲取優先順序
 public final int getPriority() {
        return priority;
    }

但在上邊的例子中,發現,主執行緒一直比子執行緒結束的早。Java中主執行緒結束後子執行緒繼續執行,但C中會報錯

所以用到了join方法

//等待執行緒die,只有這個執行緒結束後才能繼續執行後面的程式
public final void join() throws InterruptedException {
        join(0);
    }

//設定時間,若為0的話,永遠等待
public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }


 public final synchronized void join(long millis, int nanos)
    throws InterruptedException {

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (nanos < 0 || nanos > 999999) {
            throw new IllegalArgumentException(
                                "nanosecond timeout value out of range");
        }

        if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
            millis++;
        }

        join(millis);
    }
public class Main2 {

	public static void main(String[] args) {
		Thread1 thread1 = new Thread1();
		Thread t1 = new Thread(thread1);
		Thread t2 = new Thread(thread1);
		t1.start();
		t2.start();
		try {
			t1.join();
			t2.join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		System.out.println(Thread.currentThread().getName()+"主執行緒結束");
	}

}

這樣的話,主執行緒必須等這兩個執行緒全結束才能結束

yield() 暫停當前正在執行的物件,並執行其他執行緒,只是讓當前執行緒轉換為可執行狀態,以允許具有相同優先順序的執行緒獲得執行機會,但無法保證yield達到讓步的目的。

sleep() 使當前執行緒進入停滯狀態,所以執行sleep的執行緒在指定時間內肯定不會被執行

sleep()方法允許較低有優先順序的執行緒獲取執行機會,但yield()不會

Obj.wait(),與Obj.notify()必須要與synchronized(Obj)一起使用,也就是wait,與notify是針對已經獲取了Obj鎖進行操作,從語法角度來說就是Obj.wait(),Obj.notify必須在synchronized(Obj){...}語句塊內。從功能上來說wait就是說執行緒在獲取物件鎖後,主動釋放物件鎖,同時本執行緒休眠。直到有其它執行緒呼叫物件的notify()喚醒該執行緒,才能繼續獲取物件鎖,並繼續執行。相應的notify()就是對物件鎖的喚醒操作。但有一點需要注意的是notify()呼叫後,並不是馬上就釋放物件鎖的,而是在相應的synchronized(){}語句塊執行結束,自動釋放鎖後,JVM會在wait()物件鎖的執行緒中隨機選取一執行緒,賦予其物件鎖,喚醒執行緒,繼續執行。這樣就提供了線上程間同步、喚醒的操作。Thread.sleep()與Object.wait()二者都可以暫停當前執行緒,釋放CPU控制權,主要的區別在於Object.wait()在釋放CPU同時,釋放了物件鎖的控制。

但是  synchronized 到底是什麼?