Потому, что Arrays.asList() возвращает экземпляр ArrayList, использующий переданный массив. То есть вы те же самые данные просто обернули дополнительной абстракцией.
На национальность и гражданство могут обращать внимание там, где на одну вакансию десять соискателей, а когда работаешь в позиции, где на одного соискателя десять оферов, то не помешает даже похабная татуировка на лице. Так что всё только от вас зависит.
Выглядит как обычный striped lock. Берёте обычную очередь, обычный пул потоков и заполняете массив экземплярами Lock. Поток в начале работы берёт Message из очереди, получает из него SubjectId, вычисляет его хэш и пытается захватить блокировку из соответствующего хэшу элемента массива. Если блокировка удалась, поток выполняет свою работу. Если нет, возвращает Message в конец очереди и берёт следующий из начала. Остаётся только подобрать эффективный размер массива блокировок.
Перед завершение программы необходимо передавать потокам какой-либо сигнал о завершений, который они будут проверять на каждой итерации цикла и завершать его в случае необходимости, а закрытие файлов сделать после цикла.
Убирая водяные знаки, вы подтвердили свой преступный умысел. Теперь ждите, пока один из настоящих владельцев изображений не обнаружит ваш сайт. А дальше зависит от этого владельца, ленивый может просто нажаловаться вашему хостеру и поисковым системам. Более активный может подать на вас в суд.