购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

1.12 暂停线程

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

1.12.1 suspend()方法与resume()方法的使用

本节将讲述suspend()方法与resume()方法的使用。

创建测试用的项目suspend_resume_test,文件MyThread.java代码如下:

package mythread;

public class MyThread 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++;
        }
    }

}

文件Run.java代码如下:

package test.run;

import mythread.MyThread;

public class Run {

    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-54所示。

图1-54 暂停与恢复的测试

stop()方法用于销毁线程对象,如果想继续运行线程,则必须使用start()方法重新启动线程,而suspend()方法用于让线程不再执行任务,线程对象并不销毁,在当前所执行的代码处暂停,未来还可以恢复运行。

从控制台输出的时间上来看,线程的确被暂停了,而且可以恢复成运行状态。

1.12.2 suspend()方法与resume()方法的缺点——独占

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

创建suspend_resume_deal_lock项目,文件SynchronizedObject.java代码如下:

package testpackage;

public class SynchronizedObject {

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

}

文件Run.java代码如下:

package test.run;

import testpackage.SynchronizedObject;

public class Run {

    public static void main(String[] args) {
        try {
            final SynchronizedObject object = new SynchronizedObject();

            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() {
                    System.out.println("thread2启动了,但进入不了printString()方法!只打印1个begin");
                    System.out.println("因为printString()方法被a线程锁定并且永远suspend暂停了!");
                    object.printString();
                    }
            };
            thread2.start();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

程序运行结果如图1-55所示。

另外一种独占锁的情况也需要格外注意,稍有不注意,就会掉进“坑”里。创建测试用的项目suspend_resume_LockStop,类MyThread.java代码如下:

package mythread;

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

    @Override
    public void run() {
        while(true) {
            i++;
        }
    }
}

图1-55 独占并锁死

类Run.java代码如下:

package test.run;

import mythread.MyThread;

public class Run {

    public static void main(String[] args) {

        try {
            MyThread thread = new MyThread();
            thread.start();
            Thread.sleep(1000);
            thread.suspend();
            System.out.println("main end!");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

程序运行结果如图1-56所示。

图1-56 控制台输出main end信息

进程状态在控制台中呈红色按钮显示,说明进程并未销毁。虽然main线程销毁了,但是MyThread呈暂停状态,所以进程不会销毁。

但如果将线程类MyThread.java更改如下:

package mythread;

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

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

再次运行程序,控制台不输出main end,如图1-57所示。

图1-57 不输出main end信息

出现这种情况的原因是当程序运行到System.out.println(i)方法内部停止时,同步锁是不释放的,println()方法源代码如图1-58所示。

图1-58 锁不释放

当前PrintStream对象的println()方法一直呈“暂停”状态,并且“锁未释放”,而main()方法中的代码“System.out.println("main end!");”也需要这把锁,main线程并未销毁,造成迟迟不能输出main end。

虽然suspend()方法是过期作废的方法,但研究其过期作废的原因是很有必要的。

1.12.3 suspend()方法与resume()方法的缺点——数据不完整

在使用suspend()方法与resume()方法时也容易出现线程暂停,进而导致数据不完整的情况。

创建项目suspend_resume_nosameValue,文件MyObject.java代码如下:

package myobject;

public class MyObject {

    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("停止a线程!");
            Thread.currentThread().suspend();
        }
        this.password = p;
    }

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

文件Run.java代码如下:

package test;

import myobject.MyObject;

public class Run {

    public static void main(String[] args) throws InterruptedException {

        final MyObject myobject = new MyObject();

        Thread thread1 = new Thread() {
            public void run() {
                myobject.setValue("a", "aa");
            };
        };
        thread1.setName("a");
        thread1.start();

        Thread.sleep(500);

        Thread thread2 = new Thread() {
            public void run() {
                myobject.printUsernamePassword();
            };
        };
        thread2.start();

    }

}

程序运行结果如图1-59所示。

图1-59 程序运行结果

程序运行结果出现值不完整的情况,所以在程序中使用suspend()方法要格外注意。

这两个方法被标识为作废过期的,想要实现对线程进行暂停与恢复的处理,可使用wait()、notify()或notifyAll()方法。 nPCilnH2AZ7X6k1k000eXqmtAIawS8xpBDLvOo9MG+bFCYOJiqz/rG8UG9g32fPr

点击中间区域
呼出菜单
上一章
目录
下一章
×