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