当我尝试使用Java通过套接字从客户端向服务器端发送图片时,我发现了一个非常奇怪的事情。这是我在Class ImgSender客户端的代码,它扩展了Thread类:
public class ImgSender extends Thread
{
Socket img_s;
BoolFlag imageready,dataready;
ImgBoundingBox image;
ByteArrayOutputStream byteArrayOutputStream;;
public ImgSender(Socket s,BoolFlag dataready,BoolFlag imageready,ImgBoundingBox image)
{
this.img_s=s;
this.imageready=imageready;
this.image=image;
this.dataready=dataready;
}
public void run()
{
boolean running=true;
while(running)
{
// System.out.println("Img sender running");
if(imageready.getFlag())
{ System.out.println("trying to send img");
try
{
OutputStream outputStream = img_s.getOutputStream();
ImageIO.write(image.getImg(), "jpg", outputStream);
System.out.println("Send image"+System.currentTimeMillis());
outputStream.flush();
outputStream.close();
imageready.setFlag(false);
}
catch(Exception e)
{
System.out.println("image client send failed");
imageready.setFlag(false);
}
}
}
}
奇怪的是,当我评论出第一个陈述时:
System.out.println("Img sender running");
图像不会被发送到服务器,并且不会打印出“尝试发送img”。如果我没有对它进行评论,或者,我在if语句之前做了一些其他的东西,比如sleep(),可以将图片发送到服务器并打印“尝试发送img”。此外,如果我通过设置一个断点来调试程序:
if(imageready.getFlag())
然后逐步执行它,它将传递if语句并成功发送它。
就服务器端而言,这里是Class ImgManager的代码:
private class ImgManager extends Thread
{
Socket img_s;
boolean working=true;
public ImgManager(Socket s)
{
this.img_s=s;
}
public void run()
{
while(working)
{
try
{
InputStream inputStream = img_s.getInputStream();
System.out.println("Reading: " + System.currentTimeMillis());
BufferedImage image = ImageIO.read(ImageIO.createImageInputStream(inputStream));
System.out.println("Received " + image.getHeight() + "x" + image.getWidth() + ": " + System.currentTimeMillis());
ImageIO.write(image, "jpg", new File("img.jpg"));
}
catch(Exception e )
{
working=false;
System.out.println("stopped working socket");
}
}
}
public void end()
{
try
{
working=false;
img_s.close();
}
catch(Exception e)
{
System.out.println("connection close failed");
}
}
}
}
}
当它收到图像时,它会打印出图片的大小,以便我们知道它是否可以获得图像。
我在不同的机器(mac和pc windows7)和不同的软件(blueJ,eclipse甚至用命令行启动它)上尝试了这两个程序。问题表明无论在哪个环境中。
以下是存储在Google云端硬盘中的整个项目代码的链接: 服务器:https://drive.google.com/file/d/0B6w_5_wGgS14UnZCbXJKUGdvSFE/view?usp=sharing 客户端:https://drive.google.com/file/d/0B6w_5_wGgS14aUlmcG4yQWVnemM/view?usp=sharing
我认为最好下载源代码并查看其中,很难在此处描述所有内容。真诚地寻找你的帮助!
答案 0 :(得分:0)
您描述的行为:它有时有效,有时无效,取决于延迟或执行它的机器通常指向竞争条件(What is a race condition?)。
此处使用 BoolFlag
来指示处理何时开始,因此可能由不同的线程访问(setValue
和getValue
或类似)。如果我们有一个声明如下:
// b is a BoolFlag
if (b.getValue()) { // (1)
b.setValue(false); // (2)
}
然后,在(1)
执行之前,两个线程可能会在(2)
处成功完成测试。因此,为了使代码线程安全,这两个操作必须在一个步骤中执行,它们必须是 atomic 。 Java为此提供了java.util.concurrent.atomic.*
个类,例如AtomicBoolean
具有函数compareAndSet(expectedValue, newValue)
,如果操作成功,则只返回true
。当然,如您所述,您也可以使用synchronized
自行编写,并在public synchronized boolean compareAndSet(...)
实施中添加BoolFlag
。
在我说谎之前,这似乎也值得一读Volatile boolean vs AtomicBoolean