Если как ты написал "блокировка не важна", то вся эта хрень с DataAvailable вообще не нужна.
var ns = tcpClient.GetStream();
var rdr = new StreamReader(ns);
var line = rdr.ReadLine();
while (line != null) {
//обрабатываем строку...
line = rdr.ReadLine();
}
rdr.ReadLine() будет блокировать выполнение пока либо не прочитает строку либо не наткнется на конец потока.
Если тебе нужно асинхронно принимать данные по сети и "делить на строки", то подход нужен совсем другой - 1 поток просто всегда читает данные из tcpClient и записывает в буффер, 2 поток (можно и в основном), читает данные из буффера и делит на строки, если там какой-то кусок "неполный", то его надо оставить в буффере до тех пор пока остальное не придет. На самом деле и чтение из потока и обработку данных можно тоже в одном потоке делать, просто так делать не принято (хоть и будет работать)