简体   繁体   English

线程一直在运行,无法停止

[英]Thread is always running, can't stop

I want to make a test, two thread, one thread is changing the value, another thread use a while to wait the first thread, and then break and finish.But the question is the waiting thread is always running, can' stop any more. 我想进行测试,两个线程,一个线程正在更改值,另一个线程使用一段时间等待第一个线程,然后中断并完成。但是问题是等待线程始终在运行,不能再停止了。 Another question is when i open the code of "System.out.println(i + " run");", all the thread can work normally, it's so strange. 另一个问题是,当我打开“ System.out.println(i +“ run”);“的代码时,所有线程都可以正常工作,这很奇怪。

import java.util.Date;

public class ThreadTestTwo {
    public int a = 0, b = 0,c = 0;

public static void main(String[] args) {
    System.out.println(new Date()+"start");
    for (int i = 0; i < 100000; i++) {
        new ThreadTestTwo().start(i);
        if(i % 100000 == 0){
            System.out.println(i/100000);
        }
    }
    System.out.println(new Date()+"finish");
}

public void start(final int i){
    Thread readThread = new Thread(){
        @Override
        public void run() {
            while (true) {
                if(c == 1){
                    b = a;
//                      System.out.println(i+", set b "+a);
                    break;
                }
//                  System.out.println(i + " run");
            }
        }
    };
    Thread writeThread = new Thread(){
        @Override
        public void run() {
            a = 1;
            c = 1;
        }
    };
    writeThread.setName("mywrite");
    readThread.setName("myread");
    System.out.println(i+" start");
    writeThread.start();
    readThread.start();

    try {
        writeThread.join();
        readThread.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println(i+" end");
    if(b != 1)
        throw new RuntimeException("b = "+b);
}

}

The writes of one thread are NOT guaranteed to be seen for another thread unless the variables are marked as volatile or otherwise the transactions need to handled using synchronization or explicit locking 除非将变量标记为易失性,否则不保证一个线程的写入可被另一个线程看到,否则需要使用同步或显式锁定来处理事务

In your case, a,b,c are the instance variables accessed by multiple threads and the reader thread caches the values and so it doesn't see the writer thread's flushed value. 在您的情况下,a,b,c是由多个线程访问的实例变量,并且读取器线程会缓存这些值,因此看不到写入器线程的已刷新值。

Please refer the below link for more details: https://docs.oracle.com/javase/tutorial/essential/concurrency/atomic.html 请参考以下链接以获取更多详细信息: https : //docs.oracle.com/javase/tutorial/essential/concurrency/atomic.html

I advise you to read more on Threads. 我建议您阅读有关线程的更多信息。 Here it is an interesting document from O'really: http://chimera.labs.oreilly.com/books/1234000001805/ch09.html 这是来自O'really的有趣文档: http ://chimera.labs.oreilly.com/books/1234000001805/ch09.html

As for your implementation, you should be aware that the modification of one variable by a thread may not be seen by a reader thread. 对于您的实现,您应该意识到,一个线程对一个变量的修改可能不会被阅读器线程看到。 To combat that either use synchronised gets and sets, access the variables inside a synchronized block, or use an AtomicReference . 为了解决这个问题,可以使用synchronised获取和设置,访问同步块中的变量,或者使用AtomicReference You could also use a Lock such as ReantrantLock . 您还可以使用诸如ReantrantLockLock

Also, if you have two threads, in which the first is waiting for the input of the second, you could use the wait() inside a synchronized block for the first, so that the second could notify() the first one when it finishes its job. 另外,如果您有两个线程,其中第一个正在等待第二个线程的输入,则可以在第一个线程的synchronized块中使用wait() ,以便第二个线程在完成时可以notify()第一个线程它的工作。

Something like this: 像这样:

import java.util.Date;

public class ThreadTestTwo {

    private int a = 0, b = 0,c = 0;
    private final Object lock = new Object(); 
    //Any object is good as a lock, and for a simple case as this it's fine.
     //This object will work as a monitor for the synchronized blocks.

    public void start(final int i){
        Thread readThread = new Thread(){
            @Override
            public void run() {

                synchronized ( lock ) {
                    try {
                        while( c != 1 ) {
                            lock.wait();
                        }
                    }
                    catch ( InterruptedException ex ) {
                        //Exception handling
                    }

                    b = a;
                }

                //System.out.println(i + " run");

            }
        };

        Thread writeThread = new Thread(){
            @Override
            public void run() {

                synchronized ( lock ) {
                    a = 1;
                    c = 1;
                    lock.notify();
                }

            }
        };

        writeThread.setName("mywrite");
        readThread.setName("myread");
        System.out.println(i+" start");
        writeThread.start();
        readThread.start();

        System.out.println(i+" end");
    }

    public static void main(String[] args) {
        System.out.println(new Date()+"start");
        for (int i = 0; i < 100000; i++) {
            new ThreadTestTwo().start(i);
            if(i % 100000 == 0){
                System.out.println(i/100000);
            }
        }
        System.out.println(new Date()+"finish");
    }
}

I would say you don't need join() with this method. 我会说您不需要使用此方法的join() But if want to wait for the second thread to start after the first is finished, you have to use join() before starting it. 但是,如果要在第一个线程完成之后等待第二个线程启动,则必须在启动之前使用join() Like this: 像这样:

    writeThread.start();
    try {
        writeThread.join();
    }
    catch ( InterruptedException ex ) {
        //Exception handling
    }


    readThread.start();
    try {
        readThread.join();
    }
    catch ( InterruptedException ex ) {
        //Exception handling
    }

But if you use join() , for this particular case , I would say you wouldn't need any synchronized blocks or conditions, since the second thread would only start after the death of the first one. 但是,如果您使用join()对于这种特殊情况 ,我会说您不需要任何同步块或条件,因为第二个线程仅在第一个线程死后才启动。 Something like this: 像这样:

public void start(final int i){
    Thread readThread = new Thread(){
        @Override
        public void run() {
            b = a;
            //System.out.println(i + " run");

        }
    };

    Thread writeThread = new Thread(){
        @Override
        public void run() {
            a = 1;
            c = 1;

        }
    };

    writeThread.setName("mywrite");
    readThread.setName("myread");
    System.out.println(i+" start");


    writeThread.start();
    try {
        writeThread.join();
    }
    catch ( InterruptedException ex ) {
        //Exception handling
    }


    readThread.start();
    try {
        readThread.join();
    }
    catch ( InterruptedException ex ) {
        //Exception handling
    }

    System.out.println(i+" end");
}

I hope I have helped. 我希望能有所帮助。

Have a nice day. 祝你今天愉快。 :) :)

It's not a good idea to use an simple int as a signal between threads because it's not thread safe. 在线程之间使用简单的int作为信号不是一个好主意,因为它不是线程安全的。

So try to use AtomicInteger instead or make your int volatile and see what will happen. 因此,请尝试改用AtomicInteger或使您的int可变,然后看看会发生什么。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM