1.8 暫停線程
在多線程中,suspend是暫停線程,resume是恢復線程的執行.
1.8.1suspend方法和resume方法的使用
public class MyThread extends Thread {
private long i = 0L;
public long getI() {
return i;
}
public void setI(long i) {
this.i = i;
}
@Override
public void run() {
while(true) {
i++;
}
}
public static void main(String[] args) {
try {
MyThread thread = new MyThread();
thread.start();
Thread.sleep(5000);
// A段
thread.suspend();
System.out.println("A= " + System.currentTimeMillis()+" i=" + thread.getI());
Thread.sleep(5000);
System.out.println("A= " + System.currentTimeMillis()+" i=" + thread.getI());
// B段
thread.resume();
Thread.sleep(5000);
// C段
thread.suspend();
System.out.println("B= " + System.currentTimeMillis()+" i=" + thread.getI());
Thread.sleep(5000);
System.out.println("B= " + System.currentTimeMillis()+" i=" + thread.getI());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
1.8.2 suspend與resume方法的缺點-獨佔
在使用suspend與resume方法時,如果使用不當,極易造成公共的同步對象的獨佔,使得其它線程無法訪問公共同步對象.
public class SynchronizeObj {
synchronized public void printString() {
System.out.println("begin");
if(Thread.currentThread().getName().equals("a")) {
System.out.println("a 線程永遠suspend..");
Thread.currentThread().suspend();
}
System.out.println("end");
}
public static void main(String[] args) {
try {
final SynchronizeObj obj = new SynchronizeObj();
Thread thread1 = new Thread(()->obj.printString());
thread1.setName("a");
thread1.start();
Thread.sleep(500);
Thread thread2 = new Thread(()->{
System.out.println("thread2 啓動了, 但是進入不了printString,只打印一個begin");
System.out.println("因爲printString方法被a線程鎖定並且永遠suspend暫停了");
obj.printString();
});
thread2.start();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
還有另外一種獨佔鎖的情況也要格外注意,稍有不慎,就會掉進坑裏
public class MyThread extends Thread {
private long i = 0L;
public long getI() {
return i;
}
public void setI(long i) {
this.i = i;
}
@Override
public void run() {
while(true) {
i++;
}
}
public static void main(String[] args) {
try {
MyThread thread = new MyThread();
thread.start();
Thread.sleep(500);
thread.suspend();
System.out.println("main end");// 打印,但程序一直阻塞中
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
將run方法的代碼修改如下:
@Override
public void run() {
while(true) {
i++;
System.out.println(i);
}
}
再次運行發現,i被打印,但是不再打印main end,原因是當程序運行到println方法內部停止時,同步鎖未被釋放.源碼如下
/**
* Prints a long and then terminate the line. This method behaves as
* though it invokes <code>{@link #print(long)}</code> and then
* <code>{@link #println()}</code>.
*
* @param x a The <code>long</code> to be printed.
*/
public void println(long x) {
synchronized (this) {
print(x);
newLine();
}
}
1.8.3 suspend與resume方法的缺點-不同步
在使用suspend與resume方法也容易出現因爲線程的暫停而導致數據不同步的情況.
public class NoSameValue {
private String username = "1";
private String password = "11";
public void setValue(String u, String p) {
this.username = u;
if (Thread.currentThread().getName().equals("a")) {
System.out.println("stop thread A");
Thread.currentThread().suspend();
}
this.password = p;
}
public void printUsernameAndPassword() {
System.out.println(username + ":" + password);
}
public static void main(String[] args) {
try {
final NoSameValue obj = new NoSameValue();
Thread thread1 = new Thread(() -> obj.setValue("a", "aa"));
thread1.setName("a");
thread1.start();
Thread.sleep(500);
new Thread(()->obj.printUsernameAndPassword()).start();// a:11
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
1.9 yield方法
yield方法的作用是放棄當前的cpu資源,將它讓給其它的任務去佔用cpu執行時間,但放棄的時間不確定,有可能剛剛放棄,馬上又獲得cpu時間片.
public class YieldThread extends Thread{
@Override
public void run() {
long beginTime = System.currentTimeMillis();
int count = 0;
for(int i=0; i<50000000; i++) {
// Thread.yield();// 將cpu讓給其它資源導致速度變慢
count = count + (i+1);
}
long endTime = System.currentTimeMillis();
System.out.println("total time is " +(endTime - beginTime)+ " millisecond");// 21/ yield 17223
}
public static void main(String[] args) {
new YieldThread().start();
}
}