Java執行緒詳解(7)-執行緒的排程
Java執行緒:執行緒的排程-休眠
Java執行緒排程是Java多執行緒的核心,只有良好的排程,才能充分發揮系統的效能,提高程式的執行效率。
這裡要明確的一點,不管程式設計師怎麼編寫排程,只能最大限度的影響執行緒執行的次序,而不能做到精準控制。
執行緒休眠的目的是使執行緒讓出CPU的最簡單的做法之一,執行緒休眠時候,會將CPU資源交給其他執行緒,以便能輪換執行,當休眠一定時間後,執行緒會甦醒,進入準備狀態等待執行。
執行緒休眠的方法是Thread.sleep(long millis)和Thread.sleep(long millis, int nanos),均為靜態方法,那呼叫sleep休眠的哪個執行緒呢?簡單說,哪個執行緒呼叫sleep,就休眠哪個執行緒。
/** * Java執行緒:執行緒的排程-休眠 */ public class TestSleep { public static void main(String[] args) { Thread t1=new MyThread1(); Thread t2=new Thread(new MyRunnable()); t1.start(); t2.start(); } } class MyThread1 extends Thread{ @Override public void run() { for(int i=0;i<3;i++){ System.out.println("執行緒1第"+i+"次執行!"); try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } } } class MyRunnable implements Runnable{ @Override public void run() { for(int i=0;i<3;i++){ System.out.println("執行緒2第"+i+"次執行!"); try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } } }
執行結果:
執行緒1第0次執行!
執行緒2第0次執行!
執行緒2第1次執行!
執行緒1第1次執行!
執行緒2第2次執行!
執行緒1第2次執行!
從上面的結果輸出可以看出,無法精準保證執行緒執行次序。
Java執行緒:執行緒的排程-優先順序
與執行緒休眠類似,執行緒的優先順序仍然無法保障執行緒的執行次序。只不過,優先順序高的執行緒獲取CPU資源的概率較大,優先順序低的並非沒機會執行。
執行緒的優先順序用1-10之間的整數表示,數值越大優先順序越高,預設的優先順序為5。
在一個執行緒中開啟另外一個新執行緒,則新開執行緒稱為該執行緒的子執行緒,子執行緒初始優先順序與父執行緒相同。
/**
* Java執行緒:執行緒的排程-優先順序
*/
public class TestPriority {
public static void main(String[] args) {
Thread t1=new MyThread1();
Thread t2=new Thread(new MyRunnable());
t1.setPriority(10);
t2.setPriority(1);
t1.start();
t2.start();
}
}
class MyThread1 extends Thread{
@Override
public void run() {
for(int i=0;i<10;i++){
System.out.println("執行緒1第"+i+"次執行!");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class MyRunnable implements Runnable{
@Override
public void run() {
for(int i=0;i<10;i++){
System.out.println("執行緒2第"+i+"次執行!");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
執行結果:
執行緒1第0次執行!
執行緒1第1次執行!
執行緒1第2次執行!
執行緒2第0次執行!
執行緒1第3次執行!
執行緒2第1次執行!
執行緒1第4次執行!
執行緒2第2次執行!
執行緒1第5次執行!
執行緒2第3次執行!
執行緒1第6次執行!
執行緒2第4次執行!
執行緒1第7次執行!
執行緒2第5次執行!
執行緒1第8次執行!
執行緒2第6次執行!
執行緒1第9次執行!
執行緒2第7次執行!
執行緒2第8次執行!
執行緒2第9次執行!
Java執行緒:執行緒的排程-讓步
執行緒的讓步含義就是使當前執行著執行緒讓出CPU資源,但是讓給誰不知道,僅僅是讓出,執行緒狀態回到可執行狀態。
執行緒的讓步使用Thread.yield()方法,yield()為靜態方法,功能是暫停當前正在執行的執行緒物件,並執行其他執行緒。
/**
* Java執行緒:執行緒的排程-讓步
*/
public class Test {
public static void main(String[] args) {
Thread t1=new MyThread1();
Thread t2=new Thread(new MyRunnable());
t1.start();
t2.start();
}
}
class MyThread1 extends Thread{
@Override
public void run() {
for(int i=0;i<10;i++){
System.out.println("執行緒1第"+i+"次執行!");
}
}
}
class MyRunnable implements Runnable{
@Override
public void run() {
for(int i=0;i<10;i++){
System.out.println("執行緒2第"+i+"次執行!");
Thread.yield();
}
}
}
執行結果:
執行緒2第0次執行!
執行緒1第0次執行!
執行緒1第1次執行!
執行緒1第2次執行!
執行緒1第3次執行!
執行緒1第4次執行!
執行緒1第5次執行!
執行緒1第6次執行!
執行緒1第7次執行!
執行緒1第8次執行!
執行緒1第9次執行!
執行緒2第1次執行!
執行緒2第2次執行!
執行緒2第3次執行!
執行緒2第4次執行!
執行緒2第5次執行!
執行緒2第6次執行!
執行緒2第7次執行!
執行緒2第8次執行!
執行緒2第9次執行!
Java執行緒:執行緒的排程-合併
執行緒的合併的含義就是將幾個並行執行緒的執行緒合併為一個單執行緒執行,應用場景是當一個執行緒必須等待另一個執行緒執行完畢才能執行時可以使用join方法。
join為非靜態方法,定義如下:
void join()——等待該執行緒終止。
void join(longmillis)——等待該執行緒終止的時間最長為 millis毫秒。
void join(longmillis,int nanos)——等待該執行緒終止的時間最長為 millis毫秒 + nanos 納秒。
/**
* Java執行緒:執行緒的排程-合併
*/
public class Test {
public static void main(String[] args) {
Thread t1=new MyThread1();
t1.start();
for (int i = 0; i < 20; i++) {
System.out.println("主執行緒第" + i +"次執行!");
if (i>2) {
try {
///t1執行緒合併到主執行緒中,主執行緒停止執行過程,轉而執行t1執行緒,直到t1執行完畢後繼續。
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
class MyThread1 extends Thread{
@Override
public void run() {
for(int i=0;i<10;i++){
System.out.println("執行緒1第"+i+"次執行!");
}
}
}
執行結果:
主執行緒第0次執行!
主執行緒第1次執行!
主執行緒第2次執行!
主執行緒第3次執行!
執行緒1第0次執行!
執行緒1第1次執行!
執行緒1第2次執行!
執行緒1第3次執行!
執行緒1第4次執行!
執行緒1第5次執行!
執行緒1第6次執行!
執行緒1第7次執行!
執行緒1第8次執行!
執行緒1第9次執行!
主執行緒第4次執行!
主執行緒第5次執行!
主執行緒第6次執行!
主執行緒第7次執行!
主執行緒第8次執行!
主執行緒第9次執行!
主執行緒第10次執行!
主執行緒第11次執行!
主執行緒第12次執行!
主執行緒第13次執行!
主執行緒第14次執行!
主執行緒第15次執行!
主執行緒第16次執行!
主執行緒第17次執行!
主執行緒第18次執行!
主執行緒第19次執行!
Java執行緒:執行緒的排程-守護執行緒
守護執行緒與普通執行緒寫法上基本麼啥區別,呼叫執行緒物件的方法setDaemon(true),則可以將其設定為守護執行緒。
守護執行緒使用的情況較少,但並非無用,舉例來說,JVM的垃圾回收、記憶體管理等執行緒都是守護執行緒。還有就是在做資料庫應用時候,使用的資料庫連線池,連線池本身也包含著很多後臺執行緒,監控連線個數、超時時間、狀態等等。
setDaemon方法的詳細說明:
public final void setDaemon(boolean on)將該執行緒標記為守護執行緒或使用者執行緒。當正在執行的執行緒都是守護執行緒時,Java虛擬機器退出。
該方法必須在啟動執行緒前呼叫。 該方法首先呼叫該執行緒的 checkAccess方法,且不帶任何引數。這可能丟擲 SecurityException(在當前執行緒中)。 引數:on - 如果為true,則將該執行緒標記為守護執行緒。 丟擲: IllegalThreadStateException- 如果該執行緒處於活動狀態。 SecurityException- 如果當前執行緒無法修改該執行緒。 另請參見: isDaemon(),checkAccess()
/**
* Java執行緒:執行緒的排程-守護執行緒
*/
public class Test {
public static void main(String[] args) {
Thread t1=new MyCommon();
Thread t2=new Thread(new MyDaemon());
t2.setDaemon(true);//設定為守護執行緒
t2.start();
t1.start();
}
}
class MyCommon extends Thread{
@Override
public void run() {
for(int i=0;i<5;i++){
System.out.println("執行緒1第"+i+"次執行!");
try {
Thread.sleep(7);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class MyDaemon implements Runnable{
@Override
public void run() {
for (long i = 0; i < 9999999L; i++) {
System.out.println("後臺執行緒第" + i +"次執行!");
try {
Thread.sleep(7);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
執行結果:
執行緒1第0次執行!
後臺執行緒第0次執行!
後臺執行緒第1次執行!
執行緒1第1次執行!
後臺執行緒第2次執行!
執行緒1第2次執行!
後臺執行緒第3次執行!
執行緒1第3次執行!
後臺執行緒第4次執行!
執行緒1第4次執行!
後臺執行緒第5次執行!
後臺執行緒第6次執行!
後臺執行緒第7次執行!
後臺執行緒第8次執行!
後臺執行緒第9次執行!
後臺執行緒第10次執行!
從上面的執行結果可以看出:
前臺執行緒是保證執行完畢的,後臺執行緒還沒有執行完畢就退出了。
實際上:JRE判斷程式是否執行結束的標準是所有的前臺執執行緒行完畢了,而不管後臺執行緒的狀態,因此,在使用後臺縣城時候一定要注意這個問題。