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();
}
}