2015-06-24 2 views
2

Я довольно смущен термином «синхронизированный», у меня есть следующее из java-документации.Что означает синхронизация в терминах классов StringBuilder и StringBuffer?

Изменчивая последовательность символов. Этот класс предоставляет API , совместимый со StringBuffer, но без гарантии синхронизации . Этот класс предназначен для использования в качестве замены для StringBuffer в местах, где буфера строк используется одним потоком (как это обычно бывает). Если возможно, рекомендуется использовать этот класс StringBuffer, поскольку он будет быстрее в большинстве реализаций.

Как я знаю, синхронизация относится к потокам и способу их доступа.

Позволяет сказать, у меня есть веб-приложение, которое использует StringBuilder в одном из своих методов,

  • Что означает никакой гарантии синхронизации значит здесь?
  • Должен ли я беспокоиться ни о чем? Когда мне следует беспокоиться о нескольких потоках? Любые примеры?
  • Когда я должен заботиться о гарантированной и не гарантированной синхронизации?
  • Что такое пример использования веб-приложения с несколькими потоками?

Пример был бы весьма признателен.

Обратите внимание: я знаю, что для доступа к нескольким потокам требуется синхронизация, потому что они должны иметь доступ к тем же данным! Мне нужно иметь пример для этого.

ответ

2

Вы должны заботиться о синхронизации, если более одного потока может иметь доступ к одному и тому же StringBuilder экземпляру одновременно. В таком случае вам следует вместо этого использовать StringBuffer.

Например, здесь вы должны рассмотреть возможность использования StringBuffer вместо StringBuilder:

public class Test implements Runnable 
{ 
    public static StringBuilder sb = new StringBuilder(); 

    public void run() 
    { 
     Test.sb.append ("something"); 
    } 

    public static void main (String[] args) 
    { 
     // start two threads 
     new Thread (new Test()).start(); 
     new Thread (new Test()).start(); 
    } 
} 

Если у вас есть StringBuilder экземпляр, который является локальным для некоторого метода, нет никакого риска другого потока доступа к нему, так что вы не требуется синхронизация, и использование StringBuilder было бы более эффективным.

+0

Вы бы мне дали пример? что вы подразумеваете под несколькими потоками в моем примере веб-приложения? –

+0

@ DanielNewtown Например, если у вас есть статический экземпляр StringBuilder в каком-то классе, и ваше веб-приложение запускает несколько потоков, и более одного из них могут одновременно обращаться к этому экземпляру StringBuilder, вам следует синхронизировать с ним доступ. – Eran

+0

Спасибо, а какой пример веб-приложения с несколькими потоками? –

0

Вы должны заботиться об этом, если у вас есть StringBuffer, который используется совместно между потоками. Если вы не делитесь этим, то не будет никаких условий гонки, и вы можете использовать StringBuilder.

+0

Приведите пример. –

1

Синхронизированное ключевое слово не отображается в сгенерированном JavaDoc, но если вы откроете исходный код StringBuffer, вы увидите, что каждый публичный метод, который может изменить состояние экземпляра, фактически имеет синхронизированное ключевое слово в своей сигнатуре ,

Например метод getChars

/** 
    * @throws IndexOutOfBoundsException {@inheritDoc} 
    */ 
    @Override 
    public synchronized void getChars(int srcBegin, int srcEnd, char[] dst, 
             int dstBegin) 
    { 
     super.getChars(srcBegin, srcEnd, dst, dstBegin); 
    } 
1

Представьте у вас есть переменная myElement как StringBuffer. В вашем приложении есть лента новостей из разных газет, и у вас есть несколько потоков, заполняющих их из разных источников. Темы найдут новую информацию в DOM element, которую описывает myElement. Как только они обнаружат его, они изменяют myElement, поэтому другая ветка знает, где найти новую новость. Благодаря синхронизации, поток блокирует другой, когда у них есть доступ к одной и той же переменной, но не в этом случае, так что может случиться так, что один поток читает myElement, когда он изменяется, и наполовину завершен, и получает ссылку на часть DOM, которой не существует.

0

Подумайте об этом таким образом. Допустим, у вас есть класс, который совместно использует экземпляр StringBuilder между его методом. Что-то вроде этого:

public class MyClass { 
    private StringBuilder str = new StringBuilder(); 

    public void add(String str) { 
     this.str.append(str); 
    } 

    public void remove(int start, int end) { 
     this.str.delete(start, end); 
    } 

} 

Поскольку данный экземпляр является доля между несинхронизированного методом, так что если два потока, в то же время вызова эти методы данные не будут данные, которые вы ожидали. Это значение не гарантированной синхронизации.

Вместо использования StringBuilder вы можете использовать StringBuffer, который поддерживает синхронизацию.

public class MyClass { 
    private StringBuffer str = new StringBuffer(); 

    public void add(String str) { 
     this.str.append(str); 
    } 

    public void remove(int start, int end) { 
     this.str.delete(start, end); 
    } 

} 

Как известно, синхронизация имеет некоторые проблемы с производительностью, но это необходимо в случае многопоточности.

Обычно StringBuilder может использоваться как локальные переменные.

1

Использование StringBuffer почти никогда не имеет смысла:

  • большую часть времени, вы можете использовать локальную StringBuilder переменную, и есть только один поток участвует поэтому не synchronzation не требуется
  • в редкие случаи, когда переменная StringBuffer/Builder является полем и делится между потоками, в любом случае гарантия StringBuffer, вероятно, будет недостаточной, поскольку каждый вызов append будет упорядочен случайным образом LY

Представьте:

public void m(String a, String b) { 
    sharedStringBuffer.append(a).append(b); 
} 

StringBuffer не дает вам гарантию того, что каждый вызов т приведет к a и b смежно как еще один вызов, чтобы добавить могло произойти в середине. ..

Так нижняя линия:

  • либо переменная не разделяет: использовать StringBuilder
  • либо общий, и вам, возможно, потребуется больше, чем синхронизация StringBuffer: используйте StringBuilder с соответствующей синхронизацией.
+0

спасибо, что вы подразумеваете под соответствующей синхронизацией? –

+0

@ DanielNewtown - политика синхронизации, которая подходит для вашего случая использования - нет общего правила ... – assylias

0

StringBuffer не требуется, если вы не делитесь им между потоками, и в этом случае синхронизация имеет смысл. StringBuilder изменен, что означает, что состояние может просматриваться непоследовательно между потоками. StringBuffer не страдает от этой проблемы (если это вообще необходимо).

StringBuilder как StringBuffer v2. Он был добавлен в библиотеки Java после фазы, когда разработчики были параноидальными относительно безопасности потоков и требовали безопасности потоков, когда они им не нужны.

Что касается выделенной части javadoc, которую вы отправили, синхронизация имеет накладные расходы, а потому, что StringBuilder не синхронизирован, это не влияет на производительность.

гарантия синхронизации означает, что, поскольку она является «совместима с StringBuffer», вы можете ожидать StringBuilder быть синхронизированы, но может не быть в случае (например, когда JIT оптимизирует StringBuffer, например).

Вы не должны беспокоиться о не гарантированной или гарантированной синхронизации. О чем вы должны беспокоиться, это использовать StringBuffer, когда он является общим. Независимо от того, синхронизирована или не синхронизирована или не синхронизирована StringBuilder, до тех пор, пока она разделяется только внутри одного потока или защищена соответствующим образом, вы не должны сталкиваться с какими-либо проблемами.

Вы должны беспокоиться об использовании StringBuffer здесь:

final StringBuffer append = new StringBuffer(); 

void append() { 
    append.append(". "); 
} 

new Thread(() -> append()).start(); 
new Thread(() -> append()).start(); 

Вы можете видеть, что она доступна двумя потоками. Обратите внимание, как он объявлен окончательным для обеспечения безопасности инициализации.

Смежные вопросы