Почему setDaemon нужно устанавливать в блоке? И зачем он вообще нужен? Да и в целом - что тут происходит?
/**
 Исправь 2 ошибки:
 1) возникновение исключения
 2) подвисание
 Сделай минимальные изменения.

 Требования:
 1. Метод startCreatingMessages() должен без зависаний добавлять в messageQueue 100000 элементов.
 2. Исправь ошибку в строке "messageQueue.drainTo(messageQueue, MAX_BATCH_SIZE);".
 3. Метод main() не должен зависать.
 4. Вывод программы должен показывать, что все сообщения из messageQueue были перенесены в fakeDataBase.
 */
public class Solution {
    final int NUMBER_OF_THREADS = 3; // 3 треда будет обрабатывать нашу очередь
    final int MAX_BATCH_SIZE = 100; // Будем вытаскивать по 100 сообщений

    private Logger logger = Logger.getLogger(Solution.class.getName());
    private BlockingQueue messageQueue = new LinkedBlockingQueue(); // Тут будут храниться все сообщения

    private BlockingQueue fakeDatabase = new LinkedBlockingQueue();

    public static void main(String[] args) throws InterruptedException {
        // Статики во многих местах неуместны, поэтому помещаем все данные в поля класса,
        // затем создаем объект и вызываем его метод
        Solution solution = new Solution();

        solution.startCreatingMessages();
        solution.startPersistingMessages();

        Thread.sleep(100);
        solution.printResults();

        Thread.sleep(100);
        solution.printResults();

        Thread.sleep(100);
        solution.printResults();

        Thread.sleep(500);
        solution.printResults();
    }

    public void startCreatingMessages() {
        new Thread() {
            @Override
            public void run() {
                for (int i = 0; i < 100000; i++) {
                    messageQueue.add(String.valueOf(i));
                }
            }
        }.start();
    }

    public void startPersistingMessages() {
        for (int i = 0; i < NUMBER_OF_THREADS; i++) {
            new Thread() {
                private final Collection batch = new ArrayList(MAX_BATCH_SIZE);

                {
                    setDaemon(true);
                }

                @Override
                public void run() {
                    while (true) {
                        try {
                            messageQueue.drainTo(batch, MAX_BATCH_SIZE);
                            persistData(batch);
                            batch.clear();
                            Thread.sleep(1);
                        } catch (Throwable e) {
                            logger.log(Level.SEVERE, "impossible to persist a batch", e);
                        }
                    }
                }
            }.start();
        }
    }

    private void persistData(Collection batch) {
        // Представим, что тут мы коннектимся к базе данных, и сохраняем данные в нее
        // Сохранение данных по 1 записи тратит много ресурсов, поэтому делают батчем (группой по несколько)
        fakeDatabase.addAll(batch);
    }

    private void printResults() {
        System.out.println();
        System.out.println("messageQueue size is " + messageQueue.size());
        System.out.println("fakeDatabase size is " + fakeDatabase.size());
    }
}