A ma connaissance, pour les threads comme le nombre de sockets ouvertes à un instant donné, la limite est celle de l'OS sous-jacent.
Par contre, côté mémoire,la limite est purement Java. Voir l'option -Xmx pour fixer la taille max du tas Java (option que tu connais peut-être).
Si tu veux répartir ton appli sur plusieurs machines, ça peut devenir un peu compliqué, car en générale, les différents serveurs sont capables de dialoguer (ou alors ils sont commandés par une machine gateway qui sert de tour de contrôle). En Java, il te faut découper ton application sur plusieurs machines virtuelles. Ensuite, ces machines virtuelles peuvent tourner sur une seule ou sur plusieurs machines physiques, cela ne change rien à leur fonctionnement.