String in Java as synchronized genlock

 

  synchronized (("" + userId).intern()) {
            // TODO:something
   }

 

JVM memory area which has a constant pool allocation on constant pool:

  1. JDK6 version, the constant pool allocation in the permanent generation PermGen
  2. JDK7 version, the constant pool allocation in the heap Heap

String constant pool is stored in the constant pool has two types of character string data stored:

  1. Compile strings can be determined, i.e., the use of " 'delimited strings, such as String A =" 123 " , String = B". 1 "B.getStringDataFromDB + () +" 2 "+ C.getStringDataFromDB () , here, "123", "1", "2" can be determined during the compile strings are, thus into the constant pool, the B.getStringDataFromDB (), C.getStringDataFromDB () because the two data compiled during It can not be determined, so they are allocated on the heap of
  2. String using the intern () String method of operation, such as String B = B.getStringDataFromDB (). Intern () , although B.getStringDataFromDB () method to get the string is allocated on the heap, but due to the addition of the back Intern (), so the results B.getStringDataFromDB () method writes the constant pool

String constant pool of data has a characteristic: every time you take the data, if there are constant pool, take a direct data in the constant pool; if not constant pool, the data is written to the constant pool and returns the constant pool data .

This is not a big problem in jdk6 years, because String.intern () will create a space where perm, perm if there's enough space, this will not lead to frequent Full GC,

But jdk7 where the problem is big, String.intern () will create a space in the heap, but also the old era, if more than one subject will lead to Full GC long time !!!

Caution ah! Solution? Finally found it.

Here we must quote powerful google-guava package, which is not an ordinary powerful, fully make apache-commons * banned out of rhythm ah! ! !

 

Interner<String> pool = Interners.newWeakInterner();

synchronized ( pool.intern("BizCode"+userId)){

//TODO:something

}

 

This class of intern done a lot of optimization, using weak references wraps you pass the string type, so, so as not to cause a greater impact on memory, you can use the class pool.intern (str) to string intern, well, this would resolve the problem of memory, then we use the advantages and avoid memory usage issues, the perfect solution. But this will be a problem in a distributed system

//类1- SynStringTest
package com.tinygao.thread.synstring;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;

import com.google.common.base.Stopwatch;
import com.google.common.util.concurrent.ThreadFactoryBuilder;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class SynStringTest {

    private final static SynString synStr = new SynString();
    private final static Stopwatch sw = Stopwatch.createStarted();
    private static BiConsumer<SynString, String> function = (x, y)->{
        synchronized (x.getStringLock(y)) {
            log.info("Get lock: {}", y);
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    };
    public static void main(String[] args) throws InterruptedException {
        final ExecutorService executorService = Executors.newFixedThreadPool(
                4,
                new ThreadFactoryBuilder().setNameFormat("SynString-%d").build()
        );
        
        executorService.submit(()->{
            doTask("test");
        });
        executorService.submit(()->{
            doTask("test");
        });
        executorService.submit(()->{
            doTask("test1");
        });
        executorService.shutdown();
        executorService.awaitTermination(1, TimeUnit.DAYS);
        sw.stop();
    }
    
    private static void doTask(String lockStr) {
        function.accept(synStr, lockStr);
        log.info("Do get lockStr successed waste time elapsed : {} ms", sw.elapsed(TimeUnit.MILLISECONDS));
    }
}

//类2- SynString 
package com.tinygao.thread.synstring;
import java.util.concurrent.ConcurrentMap;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class SynString {

    private static ConcurrentMap<String,Object> parMap =  Maps.newConcurrentMap();
    
    public  Object getStringLock(String string) {
        Object lock = this;
        if(parMap != null) {
            Object newLock = new Object();
            lock = parMap.putIfAbsent(string, newLock);
            if(lock == null) {
                lock = newLock;
            }
        }
        return lock;
    }
    
    public static void main(String[] args) {
        Object result = parMap.putIfAbsent("h", "g");
        log.info("Get result: {}", result);
    }
}

 

Guess you like

Origin www.cnblogs.com/fswhq/p/11260896.html