java中的多线程无法进行通信变更

时间:2015-12-06 11:58:30

标签: java multithreading

我必须更改应用程序线程中的布尔变量(setReadyToUpload)并听到此更改(isReadyToUpload)另一个线程(服务器线程)将执行某些操作。虽然服务器线程处于while循环中并且检查所有时间它没有捕获我在应用程序线程中更改布尔变量时的更改。 申请线程

package server;

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ProgressIndicator;
import javafx.stage.FileChooser;

import java.io.File;

public class serverController {
serverMain main;

@FXML
private Button upload;

@FXML
private ProgressIndicator indicator;

@FXML
void pressed(ActionEvent event) {
    FileChooser fc=new FileChooser();

    File file=fc.showOpenDialog(main.getStage());


    if(file!=null) {
        main.setFileLoaction(file.getAbsolutePath());
        System.out.println("it is done");
        main.setReadyToUpload(true);

    }
    else
    {
        Alert alert=new Alert(Alert.AlertType.ERROR);
        alert.setHeaderText("Upload problem");
        alert.setContentText("You have'nt select any file to upload");
        alert.showAndWait();

    }


}
public void setMain(serverMain main) {
    this.main = main;
}

}

服务器线程

package tcpobject;


import java.io.File;
import java.util.*;

import server.serverMain;
import util.NetworkUtil;

public class WriteThreadServer implements Runnable {

private Thread thr;
private NetworkUtil nc;
private  serverMain main;
private LargeFile o;
private  LargeFileInserter lfi;
String name;

public WriteThreadServer(NetworkUtil nc,String name, serverMain main) {
    this.nc = nc;
    this.name=name;
    this.thr = new Thread(this);
    this.main=main;
    thr.start();
}

public void run() {
    while(true)
    {
        try {
            //System.out.println("it is "+main.isReadyToUpload());
            // if i print this then thelower block works good but if i dont it cant catch the change
            System.out.println("it is checking");
            if(main.isReadyToUpload())
            {
                System.out.println("it is ru");
                FileDataHandler();
            }

            if(main.isStartUpload()) {
                //System.out.println("it is su");
                LargeFileHandler();
                System.out.println("it is su");
                for (int i = 0; lfi.hasMoreBytes(); i++) {
                    o = lfi.nextByte();
                    nc.write(o);
                }
                lfi.close();

            }

        } catch(Exception e) {
            System.out.println (e+"  here");
            e.printStackTrace();
            nc.closeConnection();
        }

    }

}
void FileDataHandler ()
{

    FileDataMessage fd=new FileDataMessage(main.getFileLoaction());
    nc.write(fd);
    main.setReadyToUpload(false);

}
void LargeFileHandler ()
{

    try {
        lfi=new LargeFileInserter(main.getFileLoaction());
    } catch (Exception e) {
        e.printStackTrace();
    }
    //FileDataMessage fd=new FileDataMessage("F:\\L-2 T-1\\EEE 263\\Electronic devices and ckt theory- boylestad 11th edition.pdf");
    //System.out.println(fd);
    //System.out.println(fd.sizetoPrint());
    LargeFile o;
    main.setStartUpload(false);
}

}

所有函数和变量都写在主类中,两个线程都可以访问该类。

1 个答案:

答案 0 :(得分:2)

如果没有其他代码可用,方法setReadyToUploadisReadyToUpload会出现共享对象可见性问题,这是您设置为true的标志。

可能发生的是两个线程在不同的核心上运行,一个线程将该标志更新为true。此更新可能发生在CPU缓存中,只要更改未刷新回主内存,另一个检查该值的线程就无法读取该更新。

您可以通过以下方式修复当前设计:

a)使标志为volatile,强制更新CPU寄存器之间的高速缓存行

b)使方法同步,效果与上述相同

然而,你应该做的是使用wait和notify而不是在服务器线程中等待繁忙并浪费CPU周期。

只需创建monitor变量,例如:

private final Object monitor = new Object();

并在服务器代码中执行:

synchronized(monitor) {

    monitor.wait():
}

因此,当更改准备就绪时,您可以通过以下其他线程通知更改:

synchronized(monitor)

{
   monitor.notify();
}

服务器可以在您的客户端为Observer时实施Subject。这样您就可以通过Observer的接口方法update简单地通知更改。

请注意,理论上wait可能会被中断,因此您应该在醒来时检查是否满足条件,如果没有继续等待。