Java 静态易失性布尔-线程未终止

Java 静态易失性布尔-线程未终止,java,multithreading,concurrency,Java,Multithreading,Concurrency,我编写了一个简单的多线程应用程序,只是为了处理并发性问题,但我对控制线程中循环的布尔变量有一个问题。如果队列中没有剩余元素,其中一个函数应该停止线程,我想这是我的问题,因为如果我在大括号之间添加了一些内容: while (!queue.isEmpty()) { } isRunning = false; 因此,它变成: while (!queue.isEmpty()) { System.out.println("ASD"); } isRunning = false; 它工作得更好一点-

我编写了一个简单的多线程应用程序,只是为了处理并发性问题,但我对控制线程中循环的布尔变量有一个问题。如果队列中没有剩余元素,其中一个函数应该停止线程,我想这是我的问题,因为如果我在大括号之间添加了一些内容:

while (!queue.isEmpty()) {
}
isRunning = false;
因此,它变成:

while (!queue.isEmpty()) {
    System.out.println("ASD");
}
isRunning = false;
它工作得更好一点-程序在执行
关闭
方法后终止

有什么想法吗

以下是我的应用程序的完整代码:

package test;

public class xxx {
    public static void main(String[] args) {
        Foo instance = Foo.getInstance();
        Thread x = new Thread(instance);
        x.start();

        for (int count = 1; count < 100000; count++)
            instance.addToQueue(count + "");
        instance.turnOff();
    }
}
封装测试;
公共类xxx{
公共静态void main(字符串[]args){
Foo instance=Foo.getInstance();
线程x=新线程(实例);
x、 start();
用于(整数计数=1;计数<100000;计数++)
addToQueue(计数+“”);
实例。关闭();
}
}
以及:

封装测试;
导入java.util.LinkedList;
导入java.util.List;
公共类Foo实现了Runnable{
私有静态Foo-inner=null;
私有静态列表队列=新建LinkedList();
私有易失性静态布尔值isRunning=false;
私有Foo(){}
公共静态Foo getInstance(){
if(内部==null){
内部=新的Foo();
}
返回内部;
}
public void addToQueue(字符串toPrint){
已同步(队列){
queue.add(toPrint);
}
}
public void removeFromQueue(字符串toRemove){
已同步(队列){
队列。删除(删除);
}
}
公共空间关闭(){
而(!queue.isEmpty()){
}
系统输出打印项次(“结束”);
isRunning=false;
}
@凌驾
公开募捐{
isRunning=true;
同时(正在运行){
如果(!queue.isEmpty()){
String String=queue.get(0);
System.out.println(字符串);
removeFromQueue(字符串);
}
}
}
}

这是一个竞争条件问题。run方法(另一个线程)可能在主线程中的关闭之后执行,因此标志isRunning再次设置为true,循环永远不会结束


这就解释了为什么使用简单的System.out.println(“ASD”)会变得更好:isRunning=false被延迟。

正如Germann Arlington point所说,queue.isEmpty()的值似乎被缓存在主线程中。尝试同步它:

while (true) {
    synchronized(queue) {
        if(queue.isEmpty())
            break;
    }
} 
或者只是让队列变得不稳定:

private volatile static List<String> queue = new LinkedList<String>();
private volatile static List queue=new LinkedList();

这将解决您的问题

在turnOff()方法的while循环中也使用易失性变量isRunning


主要问题是添加/删除元素和检查队列是否为空之间的竞争条件。换言之:

synchronized
块中包装
add
remove
调用可以保证这些方法的所有调用都将按顺序执行。但是,在
synchronized
块之外还有一个访问
queue
变量的权限-它是
queue.isEmpty()
。这意味着某个线程有可能获得此调用的结果,当它在
if
块内执行操作时,其他线程可能会添加或删除元素


这段代码还有一些并发问题,如果您想讨论这些问题,请告诉我(它们有点离题)。

您的代码中有很多问题

  • 关闭
    等待
  • 关闭
    运行中的
    队列
    的非同步访问
  • 内部的非易失性、非最终访问
  • 不必要的静态
    isRunning
    queue
    变量
  • 关闭
    启动
    调用之间的竞争条件
  • 其中一些在这个特定实例中是无害的(例如,
    实例始终从主线程访问),但是根据您的硬件配置,您将被其他实例的一些组合所咬。添加
    System.out
    “修复”问题的原因是,它使一个繁忙循环变得不那么繁忙(修复1),并具有内部同步机制(修复2),但其他循环仍然存在

    我建议去掉
    isRunning
    变量和
    queue.isEmpty()
    的测试,并替换为
    CountDownLatch

    package test;
    
    import java.util.LinkedList;
    import java.util.List; 
    import java.util.concurrent.CountDownLatch;
    
    public class Foo implements Runnable {
        private static final Foo inner = new Foo();
        private final List<String> queue = new LinkedList<String>();
        private final CountDownLatch latch = new CountDownLatch(1);
    
        private Foo() { }
    
        public static Foo getInstance() {
            return inner;
        }
    
        public void addToQueue(String toPrint) {
            synchronized (queue) {
                queue.add(toPrint);
            }
        }
    
        public void removeFromQueue(String toRemove) {
            synchronized (queue) {
                queue.remove(toRemove);
            }
        }
    
        public boolean isEmpty() {
            synchronized (queue) {
                return queue.isEmpty();
            }
        }
    
        public String getHead() {
            synchronized (queue) {
                return queue.get(0);
            }
        }
    
        public void turnOff() throws InterruptedException {
            latch.await();
            System.out.println("end");
        }
    
        @Override
        public void run() {
            while (!isEmpty()) {
                String string = getHead();
                System.out.println(string);
                removeFromQueue(string);
            }
    
            latch.countDown();
        }
    }
    
    封装测试;
    导入java.util.LinkedList;
    导入java.util.List;
    导入java.util.concurrent.CountDownLatch;
    公共类Foo实现了Runnable{
    私有静态final Foo-inner=new Foo();
    私有最终列表队列=新建LinkedList();
    专用最终倒计时闩锁=新倒计时闩锁(1);
    私有Foo(){}
    公共静态Foo getInstance(){
    返回内部;
    }
    public void addToQueue(字符串toPrint){
    已同步(队列){
    queue.add(toPrint);
    }
    }
    public void removeFromQueue(字符串toRemove){
    已同步(队列){
    队列。删除(删除);
    }
    }
    公共布尔值为空(){
    已同步(队列){
    return queue.isEmpty();
    }
    }
    公共字符串getHead(){
    已同步(队列){
    返回队列。获取(0);
    }
    }
    public void turnOff()引发InterruptedException{
    satch.wait();
    系统输出打印项次(“结束”);
    }
    @凌驾
    公开募捐{
    而(!isEmpty()){
    String=getHead();
    System.out.println(字符串);
    removeFromQueue(字符串);
    }
    倒计时();
    }
    }
    
    跑步者呢

    package test;
    
    public class XXX {
        public static void main(String[] args) throws InterruptedException {
            Foo instance = Foo.getInstance();
            Thread x = new Thread(instance);
    
            for (int count = 1; count < 100000; count++)
                instance.addToQueue(count + "");
    
            x.start();
            instance.turnOff();
        }
    }   
    
    封装测试;
    公共类XXX{
    公共静态void main(字符串[]args)引发InterruptedException{
    Foo instance=Foo.getInstance();
    螺纹x=新螺纹(安装
    
    package test;
    
    import java.util.LinkedList;
    import java.util.List; 
    import java.util.concurrent.CountDownLatch;
    
    public class Foo implements Runnable {
        private static final Foo inner = new Foo();
        private final List<String> queue = new LinkedList<String>();
        private final CountDownLatch latch = new CountDownLatch(1);
    
        private Foo() { }
    
        public static Foo getInstance() {
            return inner;
        }
    
        public void addToQueue(String toPrint) {
            synchronized (queue) {
                queue.add(toPrint);
            }
        }
    
        public void removeFromQueue(String toRemove) {
            synchronized (queue) {
                queue.remove(toRemove);
            }
        }
    
        public boolean isEmpty() {
            synchronized (queue) {
                return queue.isEmpty();
            }
        }
    
        public String getHead() {
            synchronized (queue) {
                return queue.get(0);
            }
        }
    
        public void turnOff() throws InterruptedException {
            latch.await();
            System.out.println("end");
        }
    
        @Override
        public void run() {
            while (!isEmpty()) {
                String string = getHead();
                System.out.println(string);
                removeFromQueue(string);
            }
    
            latch.countDown();
        }
    }
    
    package test;
    
    public class XXX {
        public static void main(String[] args) throws InterruptedException {
            Foo instance = Foo.getInstance();
            Thread x = new Thread(instance);
    
            for (int count = 1; count < 100000; count++)
                instance.addToQueue(count + "");
    
            x.start();
            instance.turnOff();
        }
    }