首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >线程的意外行为

线程的意外行为
EN

Stack Overflow用户
提问于 2021-03-11 19:18:13
回答 2查看 112关注 0票数 3

我试图实现thread2应该首先完成,然后是thread1,为此O使用了join()方法。但是,如果我取消thread1类的try块中的thread1注释。然后代码给出空指针异常。为什么在try块中我需要添加行,添加一行代码是没有任何意义的。

演示类

代码语言:javascript
复制
public class Demo {

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

        Thread1 t1 = new Thread1();
        Thread2 t2 = new Thread2();
        t1.start();
        t2.start();

        System.out.println("main Thread");
        Thread.sleep(10);
    }
}

Thread1类

代码语言:javascript
复制
public class Thread1 extends Thread {
    @Override
    public void run() {
        try {
//            System.out.println(); // on adding anyline, this whole code works!!, uncommenting this line of code give NPE
            Thread2.fetcher.join();

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for (int i = 0; i < 5; i++) {

            System.out.println("in thread1 class, Thread-1 ");
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Thread2类

代码语言:javascript
复制
public class Thread2 extends Thread {

    static Thread fetcher;

    @Override
    public void run() {

        fetcher= Thread.currentThread(); // got the thread2
        for (int i = 0; i < 5; i++) {
            System.out.println("in thread2 class, Thread-2");
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}

程序输出

代码语言:javascript
复制
in thread2 class Thread-2
Exception in thread "Thread-0" java.lang.NullPointerException
    at org.tryout.Thread1.run(Thread1.java:22)
in thread2 class Thread-2
in thread2 class Thread-2
in thread2 class Thread-2
in thread2 class Thread-2
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-03-11 19:25:34

它纯粹靠“纯粹的运气”运作。

代码语言:javascript
复制
System.out.println();

内部调用synchronized,这是一个延迟,为Thread 2的字段fetcher提供了足够的时间:

代码语言:javascript
复制
fetcher= Thread.currentThread(); // got the thread2

为了避免这种争用条件,您需要确保Thread 2Thread 2访问字段fetcher之前设置它。为此,除其他外,还使用了一个CyclicBarrier

??一种同步辅助工具,允许一组线程都等待对方到达公共的障碍点。** CyclicBarriers在涉及固定大小线程的程序中非常有用,这些程序必须偶尔等待对方。这个屏障被称为循环,因为它可以在等待线程释放后被重用。

首先,为将要调用它的线程数量创建一个屏障,即2个线程:

代码语言:javascript
复制
CyclicBarrier barrier = new CyclicBarrier(2);

使用CyclicBarrier,您可以强制Thread 1在访问其字段fetcher之前等待Thread 2

代码语言:javascript
复制
    try {
        barrier.await(); // Let us wait for Thread 2.
        Thread2.fetcher.join();
    } catch (InterruptedException | BrokenBarrierException e) {
        // Do something 
    }

Thread 2还在设置字段fetcher之后调用该屏障,因此:

代码语言:javascript
复制
    fetcher = Thread.currentThread(); // got the thread2
    try {
        barrier.await();
    } catch (InterruptedException | BrokenBarrierException e) {
        e.printStackTrace();
    }

这两个线程将继续他们的工作,一旦都已调用的障碍。

举个例子:

代码语言:javascript
复制
public class Demo {

    public static void main(String[] args) throws InterruptedException             { 
        CyclicBarrier barrier = new CyclicBarrier(2);
        Thread1 t1 = new Thread1(barrier);
        Thread2 t2 = new Thread2(barrier);
        t1.start();
        t2.start();
        System.out.println("main Thread");
        Thread.sleep(10);
    }
}

public class Thread1 extends Thread {
    final CyclicBarrier barrier;

    public Thread1(CyclicBarrier barrier){
        this.barrier = barrier;
    }

    @Override
    public void run() {
        try {
            barrier.await();
            Thread2.fetcher.join();
        } catch (InterruptedException | BrokenBarrierException e) {
            // Do something 
        }
        for (int i = 0; i < 5; i++) {
            System.out.println("in thread1 class, Thread-1 ");
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class Thread2 extends Thread {
    static Thread fetcher;
    final CyclicBarrier barrier;

    public Thread2(CyclicBarrier barrier){
        this.barrier = barrier;
    }

    @Override
    public void run() {

        fetcher = Thread.currentThread(); // got the thread2
        try {
            barrier.await();
        } catch (InterruptedException | BrokenBarrierException e) {
            e.printStackTrace();
        }
        for (int i = 0; i < 5; i++) {
            System.out.println("in thread2 class, Thread-2");
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

如果您的代码不是用于教育目的,而且您也没有被迫使用任何特定的同步机制来进行学习。在当前上下文中,您可以简单地将thread 2作为thread 1的参数传递,并按如下方式直接调用join:

代码语言:javascript
复制
public class Demo {
    public static void main(String[] args) throws InterruptedException {
        Thread2 t2 = new Thread2();
        Thread1 t1 = new Thread1(t2);
        t1.start();
        t2.start();
        System.out.println("main Thread");
        Thread.sleep(10);
    }
}

public class Thread1 extends Thread {
    final Thread thread2;

    public Thread1(Thread thread2){
        this.thread2 = thread2;
    }

    @Override
    public void run() {
        try {
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for (int i = 0; i < 5; i++) {
            System.out.println("in thread1 class, Thread-1 ");
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class Thread2 extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("in thread2 class, Thread-2");
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
} 
票数 6
EN

Stack Overflow用户

发布于 2021-03-11 19:31:30

这应该允许您的代码正常工作。线程启动之间没有足够的时间允许fletcher初始化。

代码语言:javascript
复制
        try {
        
            Thread.sleep(500);
             
            Thread2.fetcher.join();
         }  catch (InterruptedException ie) {
         } 

对于这么简单的事情,睡眠应该是有效的。但是对于更复杂的线程,适当的同步是关键。您应该意识到,线程编程可能是编程调试中最困难的方面之一。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66589095

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档