java 多次new DataOutputStream而不关闭,线程阻塞

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java 多次new DataOutputStream而不关闭,线程阻塞相关的知识,希望对你有一定的参考价值。

我的系统需要与多个服务端建立通信连接,也就是建立多个socket用于长时间通信,然后我有一个静态方法可以通过传入参数socket向任意一个服务端发送数据,方法如下:

public static void sendTCP(Socket socket,byte[] byteArr)

if(!socket.isClosed())
DataOutputStream os = null;
try
os = new DataOutputStream(socket.getOutputStream());
os.write(byteArr);
os.flush();
catch(SocketException e)
e.printStackTrace();
catch(Exception e)
e.printStackTrace();



现在问题在于,上面的静态方法中DataOutputStream每次用完之后都未关闭。我在一个线程中循环调用该方法,长时间高频率的调用后,数据就在也发布出去了。但是线程无异常,系统无异常,只是数据不能在发出去了,调用该方法的线程栈信息显示:
"@ReportSendThread" daemon prio=6 tid=0x492b3800 nid=0x1bf8 runnable [0x4a75f000..0x4a75fc98]
java.lang.Thread.State: RUNNABLE
at java.net.SocketOutputStream.socketWrite0(Native Method)
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:92)
at java.net.SocketOutputStream.write(SocketOutputStream.java:136)
at java.io.DataOutputStream.write(DataOutputStream.java:90)
- locked <0x091aff20> (a java.io.DataOutputStream)
at java.io.FilterOutputStream.write(FilterOutputStream.java:80)
at com.pq.communicate.frontcommunicate.util.IEC103.mainMethod.Encode103.sendTCP(Encode103.java:601)
at com.pq.communicate.frontcommunicate.util.IEC103.mainMethod.ReportSendThread.run(ReportSendThread.java:76)
at java.lang.Thread.run(Thread.java:619)

Locked ownable synchronizers:
- None
现在大概知道问题的所在,可能是DataOutputStream每次实例化后都没关闭。但我试过关闭DataOutputStream,但关闭后对应的socket也被关闭了。面对这种情况,应该如何处理?如果不能避免可以怎样换个方式实现此功能

你试试用这种方法:

package chat.server.controller;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.SocketException;
import java.util.Iterator;
import java.util.Map.Entry;

import chat.server.common.CommonData;
import chat.server.controller.MessageTypeEnum;
import chat.server.model.biz.ChatHandleBiz;
import chat.server.model.biz.LoginHandle;

/**
 * 服务线程类
 * 功能:控制数据的基本收发
 * <p>编写时间:2013-06-06
 * 
 * @author 财俊
 * 
 */
public class ServerThread extends Thread

    private Socket           socket       = null;
    private DataInputStream  dis          = null;
    private DataOutputStream dos          = null;
    private String           separatorStr = "";   // 消息分隔符
    private boolean          isListen     = false;
    private String           clientName   = "";   // 该线程服务的客户端用户名

    public ServerThread(Socket socket_)
    
        try
        
            this.socket = socket_;

            // 初始化消息定界符
            separatorStr = ":::";

            // 初始化输入输出流
            dis = new DataInputStream(socket.getInputStream());
            dos = new DataOutputStream(socket.getOutputStream());

         catch(IOException e)
        
            e.printStackTrace();
        
    

    /**
     * 向除拥有本实例以外的所有用户发送广播消息
     */
    public void broadcast(String msgStr)
    
        // 遍历在线用户表
        Iterator<Entry<String, ServerThread>> iter = CommonData.getClientThreadMap().entrySet().iterator();

        while (iter.hasNext())
        
            Entry<String, ServerThread> entry = (Entry<String, ServerThread>) iter.next();
            ServerThread clientThread = (ServerThread) entry.getValue();
            if (clientThread != this)
            
                clientThread.sendData(msgStr);
            
            // String key = entry.getKey().toString();
        
    

    /**
     * 向该客户端发送消息
     * 
     * @param socket_
     * @param msgStr
     */
    public void sendData(String msgStr_)
    
        try
        
            dos.writeUTF(msgStr_);

         catch(IOException e)
        
            e.printStackTrace();
        
    

    /**
     * 获取本实例的socket对象
     * 
     * @return
     */
    public Socket getSocket()
    
        return this.socket;
    

    /**
     * 设置是否断续监听
     * @param value
     */
    public void setListen(boolean value)
    
        this.isListen = value;
    
    
    @Override
    public void run()
    
        try
        
            // 消息内容
            String msgStr = "";

            // 分隔符在字符串中的位置
            int separatorIndex = 0;

            // 是否接收消息
            isListen = true;

            while (isListen)
            
                // 接收消息
                msgStr = dis.readUTF();

                // 确定分隔符在字符串中的位置
                separatorIndex = msgStr.indexOf(separatorStr);

                // 提取消息类型
                MessageTypeEnum msgType = MessageTypeEnum.valueOf(msgStr.substring(0, separatorIndex));

                switch (msgType)
                

                /***************** 初始化客户信息 ******************/
                    case Login:
                    
                        // msgStr 格式为msgtype:::name:::sex
                        clientName = msgStr.substring(separatorIndex + 3).split(":::")[0];

                        // 交给biz层处理
                        LoginHandle.getLoginHandle().clientLoginHandle(msgStr.substring(separatorIndex + 3), this);

                        break;
                    

                    /***************** 群聊消息 ******************/
                    case GroupChat:
                    
                        // 交给biz层处理
                        ChatHandleBiz.getChatHandleBiz().groupChatHandle(msgStr.substring(separatorIndex + 3));

                        break;
                    

                    /***************** 一对一聊天消息 ******************/
                    case SingleChat:
                    
                        // 交给biz层处理
                        ChatHandleBiz.getChatHandleBiz().singleChatHandle(msgStr.substring(separatorIndex + 3));

                        break;
                    

                    default:
                        break;
                
            

         catch(SocketException e)
        
            try
            
                // 处理用户下线
                LoginHandle.getLoginHandle().ClientOffLineHandle(clientName, this);
                
                // 关闭流和连接
                dos.flush();
                dos.close();
                dis.close();
                socket.close();
                
             catch(IOException e1)
            
                e1.printStackTrace();
            
//            e.printStackTrace();
            
         catch(IOException e)
        
            e.printStackTrace();
        
    

不知道你能不能看懂这个类,大概意思是 用一个类保存一个socket 和 和socket有关的东西,一个用户就一个线程,(在线程中new 出这个类,同时也保持一个socket)

download.csdn.net/detail/tangcaijun/5556391 这是这个类的完整一个例子(也是多用户聊天通讯的),你看看吧(不算太难)

参考技术A 为什么一定要套一个DataOutputStream?直接用socket的流写不行吗?是不是socket缓冲区满了啊?另一端有在实时读取吗?本回答被提问者采纳

以上是关于java 多次new DataOutputStream而不关闭,线程阻塞的主要内容,如果未能解决你的问题,请参考以下文章

java中new对象怎么限制?

java new失败?

java中,InetAddress为啥不能new对象

java每次都new出个对象干嘛

java多线程注意事项

java创建对象时,new 出一个对象 和 = null的区别