Использование StringBuffer в нескольких потоках практически бесполезно и в действительности почти никогда не происходит.
Рассмотрим следующее
Thread1: sb.append(key1).append("=").append(value1);
Thread2: sb.append(key2).append("=").append(value2);
каждое добавление синхронизируется, но поток может прекратить работу в любой точке, поэтому вы можете использовать любую из следующих комбинаций и даже больше
key1=value1key2=value2
key1key2==value2value1
key2key1=value1=value2
key2=key1=value2value1
Этого можно избежать, синхронизируя всю строку за раз, но это лишает смысла использование StringBuffer вместо StringBuilder.
Даже если у вас правильно синхронизированное представление, это сложнее, чем просто создать локальную копию потока всей строки, например StringBuilder и одновременно записывает строки в класс, например Writer.