Java多線程中我們有一些常用的操作線程的方法,如start(),sleep(),join(),yield(),wait(),notify()和interrupt()等方法。就是這些方法我們才能啟動線程使線程完成我們想要完成的任務。我寫過一篇建立線程的部落格,其中就介紹了線程的三種狀态:就緒狀态,運作狀态和阻塞狀态。而以上一些方法的調用就是線程狀态變化的原因之一。
1.有關線程名稱的方法
我們首先來看看Thread類的一個構造方法:
public Thread(Runnable target, String name)
這個構造方法可以傳入一個Runnable類型對象和String對象。我們知道傳入的Runnable類型的對象實際上就是我們賦予這個線程的任務,而這個String對象實際上就是我們為這個線程賦予的名稱。
我們來試一試:
public class NameTest1 {
public static void main(String[] args) {
Thread thread1 = new Thread(new Runnable() {
public void run() {
System.out.println("這是線程");
}
},"Thread-user1");
}
}
那麼我們這個線程的名稱到底是不是我們所賦的名稱呢?我們就要用到檢視線程的方法了。
public final String getName()
這個方法會傳回調用這個方法的線程的線程名稱。
我們使用這個方法來檢視上面的的代碼是否賦名成功:
public class NameTest1 {
public static void main(String[] args) {
Thread thread1 = new Thread(new Runnable() {
public void run() {
System.out.println("這是線程");
}
},"Thread-user1");
System.out.println("thread1線程的名稱為:" + thread1.getName());
}
}
結果:

可以看到,我們的線程名稱與我們所賦的名稱是相同的。
那麼如果我們想要更改一個線程的名稱怎麼辦呢?就要用到這個方法:
public final synchronized void setName(String name)
這個方法會修改調用這個方法的線程的線程名稱。
我們來試一試:
public class NameTest1 {
public static void main(String[] args) {
Thread thread1 = new Thread(new Runnable() {
public void run() {
System.out.println("這是線程");
}
},"Thread-user1");
System.out.println("thread1線程的名稱為:" + thread1.getName());
thread1.setName("Thread-newName");
System.out.println("thread1線程的名稱為:" + thread1.getName());
}
}
結果:
2.sleep()方法
public static native void sleep(long millis)
這個方法Thread類的靜态方法,需要傳入一個long型資料(millis表示機關為毫秒)。這個方法會使調用它的線程(調用這個方法所在的線程)休眠,休眠時間為傳入的參數大小乘以1毫秒。
!!!注意:線程使用這個方法進入休眠時會釋放CPU資源,但不會釋放鎖。
我們來使用一下這個方法:
public class SleepTest {
public static void main(String[] args) throws InterruptedException {
Runnable runnable = new Runnable() {
private volatile int i = 0;
public void run() {
for(;;){
Thread thread = Thread.currentThread();
synchronized (this){
i++;
if(i<6){
System.out.println(thread.getName() + "線程。。。" + i);
}else {
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
};
Thread thread1 = new Thread(runnable,"Thread-test1");
Thread thread2 = new Thread(runnable,"Thread-test2");
thread1.start();
thread2.start();
}
}
結果如圖:
可以看到,此時程式無法結束,這是因為線程1休眠無法終止。而線程1休眠後,線程2卻仍然不能執行被同步的代碼塊。
2.yield()方法
public static native void yield()
這個方法是Thread類的靜态方法,這個方法會暫停調用這個方法的線程(調用這個方法所在的線程),釋放CPU資源,但不會釋放鎖。看起來這個方法和Sleep有些相似,但是它們也有差別:1.這個方法暫停時間是沒法控制的;2.暫停結束後直接進入就緒态,不會造成阻塞;3.線程因這個方法釋放的CPU資源隻能被與線程同優先級的線程獲得。
不使用這個方法:
public class YieldTest {
public static void main(String[] args) {
Runnable runnable = new Runnable() {
public void run() {
for(int i=0; i<5; i++){
// Thread.yield();
System.out.println(Thread.currentThread().getName() + "線程列印的: i = " + i);
}
}
};
new Thread(runnable,"Thread-test1").start();
new Thread(runnable,"Thread-test2").start();
new Thread(runnable,"Thread-test3").start();
}
}
結果:
去掉注釋後,使用了yield()方法後的結果:
我們可以看到使用了yield()方法後的列印是無規律的。
3.join()方法
public final void join()
該方法會使所線上程休眠,直到調用該方法的線程執行完畢之後再開始執行所線上程。
不使用該方法:
public class JoinTest {
public static void main(String[] args) throws InterruptedException {
Runnable runnable = new Runnable() {
public void run() {
String name = Thread.currentThread().getName();
synchronized (this){
Thread.yield();
System.out.println(name + "執行");
}
}
};
Thread thread1 = new Thread(runnable,"Thread-test1");
Thread thread2 = new Thread(runnable,"Thread-test2");
Thread thread3 = new Thread(runnable,"Thread-test3");
Thread thread4 = new Thread(runnable,"Thread-test4");
Thread thread5 = new Thread(runnable,"Thread-test5");
thread1.start();
// thread1.join();
thread2.start();
// thread2.join();
thread3.start();
// thread3.join();
thread4.start();
// thread4.join();
thread5.start();
// thread5.join();
}
}
不使用該方法的結果:
使用該方法的結果:
4.interrupt()方法
public void interrupt()
該方法會将線程的中斷标志位修改為true。當中斷标志位為true後,如果線程未受阻塞,那麼就隻是中斷标志位變為true;若是線程處于阻塞狀态,此時受阻線程會抛出一個異常以退出阻塞狀态,同時中斷标志位變回false。
使用這個方法:
public class InterruptTest {
public static void main(String[] args) throws InterruptedException {
Runnable runnable = new Runnable() {
public void run() {
while(true){
boolean bool = Thread.currentThread().isInterrupted();
System.out.println(Thread.currentThread().getName() + "線程是否中斷:" + bool);
if(bool){
System.out.println(Thread.currentThread().getName() + "線程阻塞");
return;
}
}
}
};
Thread thread = new Thread(runnable, "Thread-test");
thread.start();
Thread.sleep(2);
thread.interrupt();
}
}
結果:
!!!注意:interrupt()方法隻是修改了中斷标志位,實際上不會中斷線程
請看如下代碼:
public class InterruptTest {
public static void main(String[] args) throws InterruptedException {
Runnable runnable = new Runnable() {
public void run() {
while(true){
boolean bool = Thread.currentThread().isInterrupted();
System.out.println(Thread.currentThread().getName() + "線程是否中斷:" + bool);
// if(bool){
// System.out.println(Thread.currentThread().getName() + "線程阻塞");
// return;
// }
}
}
};
Thread thread = new Thread(runnable, "Thread-test");
thread.start();
Thread.sleep(2);
thread.interrupt();
}
}
結果:
可以看到此時中斷标志位為true,但是線程卻并沒有中斷。
5.wait()方法和notify()方法
這兩個方法相對于其它方法有一些特殊,而且這兩個方法一般都是成對使用,是以我把他們放在一起。
public final void wait()
該方法是Object類的成員方法,調用該方法會使線程在wait()方法的代碼處停止,線程被置入“預執行隊列”中,等待通知或中斷,同時線程釋放鎖。
!!注意:wait()方法必須在同步方法或同步代碼塊中使用。
public final native void notify()
該方法是Object類的成員方法,調用該方法後将會在調用該方法的對象的“預執行隊列”中随機挑出一個線程進行通知。該方法一般與wait()方法成對使用。還有notifyAll()方法,則會将調用該方法的對象的“預執行隊列”中是以線程進行通知。
!!注意:notify()方法必須在同步方法或同步代碼塊中使用,而且其與wait()方法成對使用時,鎖的對象必須是同一對象。
如下代碼:
public class WaitAndNotifyTest {
public static void main(String[] args) throws InterruptedException {
Runnable runnable = new Runnable() {
public void run() {
for(int i=0; i<10; i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(i == 2){
System.out.println(Thread.currentThread().getName() + "調用wait方法,開始等待");
try {
synchronized (this){
this.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "線程列印:i = " + i);
}
}
};
Thread thread1 = new Thread(runnable,"Thread-test");
thread1.start();
Thread.sleep(5000);
synchronized (runnable){
System.out.println("通知" + thread1.getName() + "線程");
runnable.notify();
}
}
}
結果:
我的所有示範代碼都上傳在github,連結:https://github.com/nodonotnodo/JavaSE-csdn