package com.jenjinstudios.io.concurrency;

import com.jenjinstudios.io.Message;
import com.jenjinstudios.io.MessageReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

/**
 * Reads incoming messages and stores them in a MessageQueue.
 *
 * @author Caleb Brinkman
 */
public class ReadTask implements Runnable
{
    private static final Logger LOGGER = LoggerFactory.getLogger(ReadTask.class);
    private final MessageQueue messageQueue;
    private final MessageReader messageReader;

    /**
     * Construct a new ReadTask that will read from the given message input stream and store the incoming messages in
     * the given MessageQueue.
     *
     * @param messageQueue The MessageQueue.
     * @param messageReader The MessageReader.
     */
    public ReadTask(MessageQueue messageQueue, MessageReader messageReader) {
        this.messageQueue = messageQueue;
        this.messageReader = messageReader;
    }

    @Override
    public void run() {
        try {
            final Message message = messageReader.read();
            messageQueue.messageReceived(message);
        } catch (IOException e) {
            messageQueue.errorEncountered(e);
            try {
                messageReader.close();
            } catch (IOException e1) {
                LOGGER.warn("Error when closing message reader", e1);
            }
        }
    }
}

package com.jenjinstudios.io.concurrency;

import com.jenjinstudios.io.Message;
import com.jenjinstudios.io.MessageReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.EOFException;
import java.io.IOException;

/**
 * Reads incoming messages and stores them in a MessageQueue.
 *
 * @author Caleb Brinkman
 */
public class ReadTask implements Runnable
{
    private static final Logger LOGGER = LoggerFactory.getLogger(ReadTask.class);
    private final MessageQueue messageQueue;
    private final MessageReader messageReader;

    /**
     * Construct a new ReadTask that will read from the given message input stream and store the incoming messages in
     * the given MessageQueue.
     *
     * @param messageQueue The MessageQueue.
     * @param messageReader The MessageReader.
     */
    public ReadTask(MessageQueue messageQueue, MessageReader messageReader) {
        this.messageQueue = messageQueue;
        this.messageReader = messageReader;
    }

    @Override
    public void run() {
        try {
            final Message message = messageReader.read();
            messageQueue.messageReceived(message);
        } catch (EOFException ignored) {
            LOGGER.info("Client disconnected");
            try {
                messageReader.close();
            } catch (IOException closeException) {
                LOGGER.warn("Error when closing message reader", closeException);
            }
        } catch (IOException e) {
            messageQueue.errorEncountered(e);
            try {
                messageReader.close();
            } catch (IOException closeException) {
                LOGGER.warn("Error when closing message reader", closeException);
            }
        }
    }
}

Add special handling for EOFException