You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@harmony.apache.org by Paulex Yang <pa...@gmail.com> on 2006/06/26 11:24:57 UTC

Re: syncronization in Charset

Tim Ellison wrote:
> Paulex Yang wrote:
>   
>> Tim,
>>
>> Good catch! But I'm afraid it not only a test defect, but also a
>> possible Harmony implementation bug.
>>
>> The JavaDoc for String says nothing about synchronization, but Charset's
>> does: " All of the methods defined in this class are safe for use by
>> multiple concurrent threads.". So it should be safe to invoke
>> Charset.encode() concurrently.
>>     
>
> Yep, so if that had been used then I would have complained differently,
> but since String doesn't claim to be thread-safe I moved it out.
>
>   
>> Looking inside the Charset.encode(CharBuffer), it has got lock on
>> itself, the cause is the system wide cached CharsetEncoder instance is
>> not synchronized[1], so if String.getBytes() always use
>> Charset.forName() to get the cached charset instance for some certain
>> encoding, the error won't happen. Probably String create a new Charset
>> every time.
>>     
>
> Agreed, if the String was not using the 'lastCharset' it will create
> multiple instances.  Not sure why it would have this churn, unless there
> was some IO on another thread or something with a different charset.
>
>   
>> Even so, I think the Charset implementation should be safe
>> according to spec, so I suggest to also hold lock on the cached
>> CharsetEncoder during Charset.encode() so that this method is safe
>> enough to be used concurrently.
>>
>> comments?
>>     
>
> Yes, all instances of Charset should safely use the cached
> encoders/decoders.  You may then also be able to reduce the
> synchronization of the Charset itself (it would be redundant, but would
> not matter if two instances cache the same encoder simultaneously).
>   
+1, the Charset.decode() has same issue, I'll raise a JIRA and create 
patch for this.
> Regards,
> Tim
>
>
>   
>> [1] code fragment from Charset.encode()
>> synchronized public final ByteBuffer encode(CharBuffer buffer) {
>>       CharsetEncoder e = getCachedCharsetEncoder(canonicalName);
>>      ...
>>       try {
>>             // e is not safe for concurrent use
>>            return e.encode(buffer);
>>       } catch (CharacterCodingException ex) {
>>            throw new Error(ex.getMessage(), ex);
>>       }
>> }
>>
>> Tim Ellison wrote:
>>     
>>> The failing test does this (amongst other things):
>>>
>>>         final int THREAD_NUM = 20;
>>>         Thread[] thread = new Thread[THREAD_NUM];
>>>         for (int i = 0; i < THREAD_NUM; i++) {
>>>             thread[i] = new Thread() {
>>>                 public void run() {
>>>                     try {
>>>                         sink
>>>                                 .write(ByteBuffer.wrap("bytes"
>>> *****                                   .getBytes(ISO8859_1)));
>>>                     } catch (IOException e) {
>>>                         throw new RuntimeException(e);
>>>                     }
>>>                 }
>>>             };
>>>         }
>>>         for (int i = 0; i < THREAD_NUM; i++) {
>>>             thread[i].start();
>>>         }
>>>
>>> If String#getBytes(String) is not thread safe then we are doomed ;-)
>>>
>>> How about:
>>>
>>>
>>> @@ -104,14 +104,13 @@
>>>      public void test_write_LByteBuffer_mutliThread() throws IOException,
>>>              InterruptedException {
>>>          final int THREAD_NUM = 20;
>>> +        final byte[] strbytes = "bytes".getBytes(ISO8859_1);
>>>          Thread[] thread = new Thread[THREAD_NUM];
>>>          for (int i = 0; i < THREAD_NUM; i++) {
>>>              thread[i] = new Thread() {
>>>                  public void run() {
>>>                      try {
>>> -                        sink
>>> -                                .write(ByteBuffer.wrap("bytes"
>>> -                                        .getBytes(ISO8859_1)));
>>> +                        sink.write(ByteBuffer.wrap(strbytes));
>>>                      } catch (IOException e) {
>>>                          throw new RuntimeException(e);
>>>                      }
>>>
>>>
>>> Regards,
>>> Tim
>>>
>>>
>>> Apache Harmony Build wrote:
>>> <snip>
>>>  
>>>       
>>>>      [exec]     [junit] java.lang.IllegalStateException
>>>>      [exec]     [junit]     at
>>>> java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:480)
>>>>      [exec]     [junit]     at
>>>> java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:347)
>>>>      [exec]     [junit]     at
>>>> java.nio.charset.Charset.encode(Charset.java:639)
>>>>      [exec]     [junit]     at
>>>> java.lang.String.getBytes(String.java:838)
>>>>      [exec]     [junit]     at
>>>> org.apache.harmony.tests.java.nio.channels.SinkChannelTest$1.run(SinkChannelTest.java:112)
>>>>
>>>>      [exec]     [junit] Tests FAILED
>>>>     
>>>>         
>>>   
>>>       
>>     
>
>   


-- 
Paulex Yang
China Software Development Lab
IBM



---------------------------------------------------------------------
Terms of use : http://incubator.apache.org/harmony/mailing.html
To unsubscribe, e-mail: harmony-dev-unsubscribe@incubator.apache.org
For additional commands, e-mail: harmony-dev-help@incubator.apache.org