javax.sound is not good for low-latency sound, and I doubt it ever will be.
I suspect this is partially due to the way JXS polls for audio, partially because of the size of buffers that JXS uses internally, and partially because of the (relative) inefficiency of copying audio data from native structures through JNI to Java byte[] (would be nice if JXS had support ByteBuffer), and partially because of the need for TargetDataLine.read() and SourceDataLine.write() -- which are backed by JNI methods (Java methods marked with 'native' keyword) to be called very frequently and complete consistently very quickly to keep latency low. Even if you find a way to reduce latency further, it will almost certainly increase CPU consumption to unacceptably high levels.
Anyway, the two things you could play around with are:
1) Reduce the size of the byte[] that you pass to
TargetDataLine.read. The smaller you make this buffer size, the sooner you will get your first chunk of audio recorded, so that you can start playing it back sooner. However, making this buffer smaller has a cost: it will increase CPU consumption, which could have the ultimate impact of increasing latency, rather than reducing it, and the amount of CPU usage could be unacceptable because it slows the entire computer down, not just your Java program. Even worse, chewing up too much CPU can and eventually will cause audio to skip and sound bad. So the only possibility here is tuning the buffer size by trial and error to your computer's unique performance characteristics. Small enough to reduce latency, but not so small that the CPU usage causes problems.
2) Play around with the bufferSize argument that can be passed to
TargetDataLine.open and
SourceDataLine.open. The impact of tuning this value is less certain. Lowering it may reduce latency, but going too small may audio to skip and sound bad.
For lower latency audio, you may have to go to native code.