java 多執行緒 之Thread
參考部落格
根據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 到底是什麼?