Сделать класс потокобезопасным - это чертовски сложно сделать.
Первый, наивный способ, который многие пытаются использовать, - это просто добавить блокировку и убедиться, что ни один код, касающийся изменяемых данных, не сделает этого без использования блокировки. Под этим я подразумеваю, что все в классе, подлежащем изменению, должно сначала заблокировать блокирующий объект, прежде чем касаться данных, будь то чтение или запись в него.
Однако, если это ваше решение, то вам, вероятно, вообще ничего не нужно делать с кодом, просто документально подтвердите, что класс не является поточно-ориентированным, и предоставьте его программисту, который его использует.
Почему?
Потому что вы фактически только что сериализовали весь доступ к нему. Два потока, которые пытаются использовать класс одновременно, даже если они касаются отдельных его частей, будут блокироваться. Один из потоков получит доступ, другой будет ожидать завершения первого.
Это на самом деле препятствует многопоточному использованию вашего класса, поэтому в этом случае вы добавляете накладные расходы на блокировку для вашего класса, а не получаете от этого никаких преимуществ. Да, ваш класс теперь «потокобезопасен», но на самом деле он не очень хороший гражданин.
Другой способ - начать добавлять гранулярные блокировки или писать конструкции без блокировок (очень сложно), чтобы, если две части объекта не всегда были связаны, код, обращающийся к каждой части, имел свою собственную блокировку. Это позволило бы нескольким потокам, которые обращаются к различным частям данных, работать параллельно, не блокируя друг друга.
Это становится трудным везде, где вам нужно работать с более чем одной частью данных за раз, так как вам нужно быть очень осторожным, чтобы взять блокировки в правильном порядке или избежать взаимоблокировок. Ваш класс должен нести ответственность за обеспечение того, чтобы блокировки были приняты в правильном порядке, а не код, который использует класс.
Что касается вашего конкретного примера, мне кажется, что части, которые будут меняться от фоновых потоков, являются только логическими значениями "подключено к устройству". В этом случае я бы сделал это поле изменчивым и использовал бы блокировку вокруг каждого. Однако, если список устройств изменится с фоновых потоков, вы быстро столкнетесь с проблемами.
Сначала вы должны попытаться определить все части, которые будут изменены фоновыми потоками, а затем разработать сценарии того, как вы хотите, чтобы изменения распространялись на другие потоки, как реагировать на изменения и т. Д.