Что вы делаете неправильно, так это то, что ввод из / dev / null ведет себя как 0-байтовый файл, и поэтому процесс достигает EOF при стандартном вводе и завершается. Если / dev / null может содержать процесс, ожидающий ввода, это будет работать:
$ cat < /dev/null
Но, конечно же, кот сразу же выходит.
Вас укусила проблема, что у вас есть программа с потоками, которая читает из TTY. Как только вы справитесь с ним, поскольку он читает из TTY, драйвер tty отправляет ему SIGTTIN, который останавливает все его потоки.
Я бы просто переосмыслил эту программу. Если вы хотите, чтобы программа работала в фоновом режиме, не читайте ввод пользователя как сигнал завершения. Избавьтесь от этого чтения и убейте его сигналами, когда вы хотите, чтобы оно прекратилось.
Если вы хотите, чтобы оба поведения (фоновый режим и режим пользовательского выхода) были настроены во время выполнения программы. Одним из способов было бы просто определить, является ли стандартный ввод устройством TTY или нет. Если это устройство TTY, выполните чтение и выход TTY. Если это не TTY, не читайте: вместо этого сделайте бесконечный сон. Тогда ваш стандартный прием ввода / dev / null должен работать. / dev / null не является TTY, поэтому процесс будет просто спать.
(У вас есть функция isatty в Java?)