java 暂停线程

暂停线程 暂停线程意味着此线程还可以恢复运行。在Java多线程中,suspend()方法可以暂停线程,resume()方法可以恢复线程。 这两个方法都是已经过时的方法。 1.8.1suspend与resume方法的使用 package cn.zxyy.multiThread.Thread.suspendThread; public class MyThread

暂停线程

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

这两个方法都是已经过时的方法。

1.8.1suspend与resume方法的使用

package cn.zxyy.multiThread.Thread.suspendThread;

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++;
        }
    }
}

package cn.zxyy.multiThread.Thread.suspendThread;

public class MyThreadTest {
    public static void main(String[] args) {
        try{
            MyThread myThread = new MyThread();
            myThread.start();
            Thread.sleep(5000);//主线程睡觉5秒,myThread开始运行,计算i的值,
            myThread.suspend();//然后myThread线程暂停了,主线程睡完5秒后,又开始执行就打印下面的i值
            System.out.println("A = " + System.currentTimeMillis() + " i = " +myThread.getI());
            Thread.sleep(5000);//打印之后又睡5秒,
            System.out.println("A = " + System.currentTimeMillis() + " i = " +myThread.getI());//这里我们可以看到i值没有发生变化,说明myThread线程被暂停了
            myThread.resume();//使myThread线程恢复运行状态
            Thread.sleep(5000);//主线程睡5秒,这时myThread线程在运行
            myThread.suspend();
            System.out.println("B = " + System.currentTimeMillis() + " i = " +myThread.getI());//再次打印i值发生变化,说明这5秒myThread线程已经被恢复了,并且在运行
            Thread.sleep(5000);//主线程再睡5秒,myThread线程被暂停

            System.out.println("B = " + System.currentTimeMillis() + " i = " +myThread.getI());//这时再对myThread线程暂停,它又开始不计算值
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

从运行结果上看,在 主线程休眠的5秒钟内,myThread线程一直在运行,主线程休眠完毕后,调用suspend方法使myThread线程暂停,myThread线程暂停运行。主线程再次休眠5秒,这5秒内,myThread线程还处于暂停状态,直到resume方法被调用,myThread线程才重新开始运行。

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

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

package cn.zxyy.multiThread.Thread.suspendThread;

public class SynchronizedObject {
    synchronized public void printString(){
        System.out.println("begin");
        if("a".equals(Thread.currentThread().getName())){
            System.out.println("a线程永远suspend了");
            Thread.currentThread().suspend();
        }
        System.out.println("end");
    }
}

 

package cn.zxyy.multiThread.Thread.suspendThread;

public class Run2 {
    public static void main(String[] args) {
        try{
            final SynchronizedObject synchronizedObject = new SynchronizedObject();
            Thread thread1 = new Thread(){
                @Override
                public void run() {
                    synchronizedObject.printString();
                }
            };
            thread1.setName("a");
            thread1.start();
            Thread.sleep(1000);
            Thread thread2 = new Thread(){
                @Override
                public void run() {
                    System.out.println("thread2启动了,但是进入不了printString方法,");
                    System.out.println("因为thread1拿到了synchronized锁,但是一直没有释放");
                    synchronizedObject.printString();
                }
            };
            thread2.start();
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

从运行结果上分析,printString方法时同步方法,也就是说该方法的锁对象是当前的object对象,创建多个线程并启动,当a线程开始执行run方法,打印begin后,a线程进入了暂停状态,这时它还在持有锁,并没有释放锁,所以当b线程启动后,进入run方法,可以执行前两句代码,但是等到执行printString方法的时候,由于a线程没有释放锁,所以线程b拿不到锁,无法进入printString方法。

所以同步方法持有锁对象才能进入,上面的方法时我们自己定义的,可以避免,还有一些Java中提供的代码,可能稍不注意,也会导致独占的情况,举个例子,我们先来看下面的代码执行:

public class MyThread2 extends Thread {
    private int i = 0;

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

 

package cn.zxyy.multiThread.Thread.suspendThread;

public class MyThread2Test {
    public static void main(String[] args) {
        try{
            MyThread2 thread = new MyThread2();
            thread.start();
            Thread.sleep(1000);
            thread.suspend();
            System.out.println("main end ");//打印了main end
        }catch (InterruptedException e){
            e.printStackTrace();
        }

    }
}

   

修改代码再次运行:

public class MyThread2 extends Thread {
    private int i = 0;

    @Override
    public void run() {
        while(true){
            i++;
            System.out.println(i);//如果加上了sout(i),那么就被独占了,因为println方法有synchronized修饰,所以无法释放锁,就不再打印main end了
        }
    }
}

从上面两个图看运行结果,为什么左图打印了"main end",而右图没有打印呢?

原因是println方法,看看println方法的源码:

从源码中可以看到,println方法内部是同步代码块,也就是说 当thread线程执行到打印语句时,会拿到一个锁,然后thread线程被暂停了,锁没有释放,主线程也有println方法,它这时候是拿不到锁的,所以这里也会出现独占的问题。

1.8.3 suspend与resume方法的缺点----不同步

package cn.zxyy.multiThread.Thread.suspendAndResume;

public class MyObject {
    private String username = "1";
    private String password = "11";

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

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

package cn.zxyy.multiThread.Thread.suspendAndResume;

public class MyObjectTest {
    public static void main(String[] args) {
        try{
            final MyObject obj = new MyObject();
            Thread thread1 = new Thread(){
                @Override
                public void run() {
                    obj.setValue("a","aa");
                }
            };
            thread1.setName("a");
            thread1.start();
            Thread.sleep(1000);
            Thread thread2 = new Thread(){
                @Override
                public void run() {
                    obj.printUsernamePassword();
                }
            };
            thread2.start();
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

从运行结果可以看到,两个线程启动会调用设置值和获取值的方法,出现了脏读的情况,这是因为suspend的方法和resume方法不同步造成的,也就是说当线程a只修改了username的时候,线程b已经运行,获取的值就是新的username,而password还是旧值。

总结:虽然suspend方法和resume方法都已经过时,但是我们需要知道它的缺点:

1.suspend方法暂停线程时,如果有锁的情况不会释放锁,容易造成其他线程无法持有锁,而无法进入run方法。

2.suspend方法和resume方法不是同步方法,可能造成脏读环境。

知秋君
上一篇 2024-07-05 20:02
下一篇 2024-07-05 19:36

相关推荐