暂停线程意味着此线程还可以恢复运行。在java多线程中,可以使用suspend()方法暂停线程,使用resume()方法恢复线程的执行。

public class Thread08 extends Thread {
    private long i = 0;

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

private static void thread08() {
    try{
        Thread08 thread = new Thread08();
        thread.start();
        Thread.sleep(5000);
        // A 
        thread.suspend(); // stop thread
        log("A=" + System.currentTimeMillis() + " i=" + thread.getI());
        Thread.sleep(5000);
        log("A=" + System.currentTimeMillis() + " i=" + thread.getI());
        // B
        thread.resume(); // restart thread
        Thread.sleep(5000);
        // C
        thread.suspend(); //stop thread
        log("B=" + System.currentTimeMillis() + " i=" + thread.getI());
        Thread.sleep(5000);
        log("B=" + System.currentTimeMillis() + " i=" + thread.getI());

    } catch(InterruptedException e) {
        e.printStackTrace();
    }
}

输出结果:

A=1496460488867 i=2618846879
A=1496460493868 i=2618846879
B=1496460498874 i=5229661166
B=1496460503876 i=5229661166

程序并没有退出,还在等待状态。

suspend与resume方法的缺点--独占

在使用suspend与resume方法时,如果使用不当,极易造成公共的同步对象的独占,使得其他线程无法访问公共同步对象。

public class Thread09 {

    // 同步资源
    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) {
    thread09();
}

private static void thread09() {
    try{
        final Thread09 object = new Thread09();
        Thread thread1 = new Thread() {
            @Override
            public void run() {
                object.printString();
            }
        };
        thread1.setName("a");
        thread1.start();
        Thread.sleep(1000);
        Thread thread2 = new Thread(){
            @Override
            public void run() {
                log("thread2 启动了,但进入不了printString方法,只打印了一个begin!");
                log("因为printString方法被a线程锁定并且永远suspend暂停了!");
                object.printString();
            }
        };
        thread2.start();

    } catch(InterruptedException e) {
        e.printStackTrace();
    }
}

输出结果:

begin
a线程永远 suspend 了!
thread2 启动了,但进入不了printString方法,只打印了一个begin!
因为printString方法被a线程锁定并且永远suspend暂停了!

程序并没有退出,还在等待状态。

还有另一种独占锁得情况也要格外注意。

public class Thread10 extends Thread {
    private long i = 0;

    @Override
    public void run() {
        while(true) {
            i++;
            System.out.println("i=" + i);
        }
    }
}

public static void main(String[] args) {
    thread10();
}

private static void thread10() {
    try{
        Thread10 thread = new Thread10();
        thread.start();
        Thread.sleep(1000);
        thread.suspend();
        log("main end!");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

输出结果:

......
i=129960
i=129961
i=129962
i=129963
i=129964

并没有输出 main end,因为
System.out.println()方法源码如下,Thread10对象suspend暂停得时候不会释放System.out.println()的同步锁,所以main方法就一直得不到System.out.println()的同步锁,也就一直不打印main end了。

public void println(String x) {
    synchronized (this) {
        print(x);
        newLine();
    }
}

suspend造成的数据不同步问题

public class Thread11 {

    private String username = "name";
    private String password = "pwd";

    public void setValue(String u, String p) {
        this.username = u;
        if(Thread.currentThread().getName().equals("a")) {
            System.out.println("停止 a 线程!");
            Thread.currentThread().suspend();
        }
        this.password = p;
    }

    public void printUP() {
        System.out.println(username + " " + password);
    }
}


public static void main(String[] args) {
    thread11();
}

private static void thread11() {
    try{
        final Thread11 object = new Thread11();
        Thread thread1 = new Thread() {
            @Override
            public void run() {
                object.setValue("a_name", "a_pwd");
            }
        };
        thread1.setName("a");
        thread1.start();
        Thread.sleep(500);
        Thread thread2 = new Thread() {
            @Override
            public void run() {
                object.printUP();
            }
        };
        thread2.start();
    } catch(InterruptedException e) {
        e.printStackTrace();
    }
}

输出结果:

停止 a 线程!
a_name pwd

程序并没有退出,还在等待状态。

可以看到以上输出的password是初始化时的值,thread1并没有赋值成功,只是赋值了username的值。

yield()方法的作用是放弃当前的CPU资源,将它让给其他的任务去占用CPU的执行时间。但放弃的时间不确定,有可能刚刚放弃,马上有获得CPU时间片。

public class Thread12 extends Thread{

    @Override
    public void run() {
        long beginTime = System.currentTimeMillis();
        int count = 0;
        for(int i = 0; i < 1000000; ++ i) {
//          Thread.yield();
            count = count + (i + 1);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("用时:" + (endTime - beginTime) + "毫秒!");
    }

}


public static void main(String[] args) {
    thread12();
}

private static void thread12() {
    Thread12 thread = new Thread12();
    thread.start();
}

输出结果:

用时:4毫秒!

解开Thread.yield();注释再次运行:

用时:213毫秒!