zoukankan      html  css  js  c++  java
  • Java中String做为synchronized同步锁

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

    JVM内存区域里面有一块常量池,关于常量池的分配:

    1. JDK6的版本,常量池在持久代PermGen中分配
    2. JDK7的版本,常量池在堆Heap中分配

    字符串是存储在常量池中的,有两种类型的字符串数据会存储在常量池中:

    1. 编译期就可以确定的字符串,即使用""引起来的字符串,比如String a = "123"String b = "1" + B.getStringDataFromDB() + "2" + C.getStringDataFromDB()、这里的"123"、"1"、"2"都是编译期间就可以确定的字符串,因此会放入常量池,而B.getStringDataFromDB()、C.getStringDataFromDB()这两个数据由于编译期间无法确定,因此它们是在堆上进行分配的
    2. 使用String的intern()方法操作的字符串,比如String b = B.getStringDataFromDB().intern(),尽管B.getStringDataFromDB()方法拿到的字符串是在堆上分配的,但是由于后面加入了intern(),因此B.getStringDataFromDB()方法的结果,会写入常量池中

    常量池中的String数据有一个特点:每次取数据的时候,如果常量池中有,直接拿常量池中的数据;如果常量池中没有,将数据写入常量池中并返回常量池中的数据

    这个在jdk6里问题不算大,因为String.intern()会在perm里产生空间,如果perm空间够用的话,这个不会导致频繁Full GC,

    但是在jdk7里问题就大了,String.intern()会在heap里产生空间,而且还是老年代,如果对象一多就会导致Full GC时间超长!!!

    慎用啊!解决办法?终于找到了。

    这里要引用强大的google-guava包,这个包不是一般的强大,是完全要把apache-commons*取缔掉的节奏啊!!!

    Interner<String> pool = Interners.newWeakInterner();
    
    synchronized ( pool.intern("BizCode"+userId)){
    
    //TODO:something
    
    }

    该类对 intern 做了很多的优化,使用弱引用包装了你传入的字符串类型,所以,这样就不会对内存造成较大的影响, 可以使用该类的 pool.intern(str) 来进行对字符串intern, 好了,这样就解决了内存的问题了,那么我们使用了该优点,并且避免了内存占用问题,完美解决。但这种在分布式系统中会有问题

    //类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);
        }
    }
  • 相关阅读:
    ZooKeeper 相关知识
    zookeeper 启动和停止脚本
    es 6.4.3 版本的es的处理方式
    SpringBoot启动使用elasticsearch启动异常:Received message from unsupported version:[2.0.0] minimal compatible
    windows下安装elasticsearch-6.4.3和elasticsearch-head插件
    二项式公式
    计算公式
    大规模数据如何检索?
    设计数据服务:为报表服务提供服务接口
    win10 桌面快捷键技术
  • 原文地址:https://www.cnblogs.com/fswhq/p/11260896.html
Copyright © 2011-2022 走看看