private void shutdown() {
        logger.config("Shutting down..");
        // Close the packetworker
        if(packetWorker.isRunning()){
            packetWorker.setRunning(false);
        }
        // Close the taskWorker
        if(!singleThreaded){
            if(taskWorker.isRunning()){
                taskWorker.setRunning(false);
            }
        }
        // Cancel all pending timeouts
        if(toWorker.isRunning()){
            toWorker.setRunning(false);
        }
        // Close all channels registered with the selector
        // This automatically invalidates the keys, so we dont
        // need to invalidate them ourselves
        Set<SelectionKey> keys = selector.keys();
        for (SelectionKey key : keys) {
            if (key.channel().isOpen()) {
                closeSocket(container.getSocket(key.channel()));
            }
        }
        // After all sockets are closed, clear pending changes.
        // Pending data associated with the sockets has already been invalidated
        // by the closeSocket() method
        synchronized (this.pendingChanges) {
            pendingChanges.clear();
        }
        // Close the selector too
        try {
            selector.close();
        } catch (IOException ioe) {
            // Ignore
        }
    }