Java中關於線程提供了Thread類和Runnable接口,二者都包含run()方法來執行線程,常用的方法列舉如下:
線程的創建和停止
可以通過繼承Thread類來新建一個線程類,也可以通過將類實現Runnable接口來新建。線程擁有name屬性來標識,可以調用setName()方法來設置,也可以在新建Thread對象時調用構造方法傳入字符串爲線程命名。Thread類內可以使用getName()獲取線程的名字,實現Runnable則沒有此方法,可以使用Thread.currentThread().getName()來得到名字。無論是繼承Thread類還是實現Runnable接口,都需要重載run()方法,在run()中定義線程所進行的操作。在創建線程對象之後,通過調用start()方法就會開始執行run()中的內容。
線程的停止不能使用stop()或者interrupt(),而應該在子線程中設置標誌來控制線程的執行。例如在子線程內通過volatile變量來控制子線程的循環,如果需要停止,可以在主進程中訪問該變量,將其設爲false來結束循環。這樣子進程可以繼續執行之後的內容,進行清理工作等,然後結束子進程。
如下所示在主進程首先創建兩個低級別線程thread1、thread2,通過start()啓動後交替執行,每執行一次就會通過yield()讓出處理器,再次進行競爭。之後通過runFlag手動停止兩個低級別線程,然後創建並執行高級別線程highThread。最後等待highThread執行結束後,結束主進程。
//低級進程類
public class LowThread implements Runnable {//通過實現接口來新建線程類
volatile boolean runFlag = true; //通過標記來控制循環的執行
@Override
public void run() {
int count = 1;
String threadName=Thread.currentThread().getName();
while (runFlag) {
System.out.println(threadName + "線程循環次數:" + count++);
Thread.yield(); //每循環一次讓出處理器,重新和其他線程競爭處理器
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(threadName+"執行結束");
}
}
//高級進程類
public class HighThread extends Thread { //通過繼承Thread類來新建一個線程類
public void run() {
System.out.println(getName() + "執行!"); //Thread類內通過getName()獲取線程名
}
}
//主進程
public class RunThread {
public static void main(String[] args) throws InterruptedException {
LowThread thread1Run=new LowThread(); //新建RUnnable對象
Thread thread1=new Thread(thread1Run,"線程1"); //使用Runnable對象初始化Thread
thread1.start(); //線程啓動,自動執行run()方法
LowThread thread2Run=new LowThread();
Thread thread2=new Thread(thread2Run,"線程2");
thread2.start();
Thread.sleep(50); //主線程休眠讓出處理器,讓thread1和2使用處理器執行
System.out.println("高級線程切入");
thread1Run.runFlag=false; //在線程外通過volatile變量控制低級線程停止
thread2Run.runFlag=false;
HighThread highThread=new HighThread();
highThread.setName("高級別線程");
highThread.start();
highThread.join(); //讓其他線程等待直到高級線程執行結束,否則會先執行主線程,輸出下一句
System.out.println("主線程執行結束");
}
}
運行情況如下所示,可以看到在高級進程首先結束,子進程在主進程之後停止,可以做相關清理等工作。
線程互斥和同步
Java通過新建一個Object鎖來控制對於臨界資源的訪問。通過synchronized關鍵字來控制同步,在進入臨界區時首先進行條件判斷,如果滿足則進入,否則將線程放入等待區wait set,之後執行臨界區代碼,執行結束後調用notify()/notifyAll()通知其他進程再次進行資源爭奪。
private final Object lockObj = new Object();
synchronized (lockObj) {
//進入臨界區的條件判斷
while (條件) {
try {
//條件不滿足, 將當前線程放入Wait Set
lockObj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//執行臨界區代碼
func();
//喚醒所有在lockObj對象上等待的線程
lockObj.notifyAll();
}