Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/363.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何在多线程应用程序中使用区域设置来提高性能_Java_Multithreading - Fatal编程技术网

Java 如何在多线程应用程序中使用区域设置来提高性能

Java 如何在多线程应用程序中使用区域设置来提高性能,java,multithreading,Java,Multithreading,在我的应用程序中,我有一个由多个线程同时调用的方法。每个线程在运行时多次调用此方法 private Locale trLoc = new Locale("tr", "TR"); public double calculate(String arg1){ arg1 = arg1.toUpperCase(trLoc); ... } 此方法进行String.toUpperString(Locale)调用,由于Locale类中的HashTable用法,导致瓶颈。当toUpperCase方法运

在我的应用程序中,我有一个由多个线程同时调用的方法。每个线程在运行时多次调用此方法

private Locale trLoc = new Locale("tr", "TR");

public double calculate(String arg1){
    arg1 = arg1.toUpperCase(trLoc);
...
}
此方法进行
String.toUpperString(Locale)
调用,由于Locale类中的
HashTable
用法,导致瓶颈。当
toUpperCase
方法运行时,每个线程等待另一个线程。这种情况使我的应用程序速度降低了三倍

在使用区域设置时,我是否缺少一些东西,或者我必须使用另一个类来实现同样的目的


提前感谢。

编辑:下面的解决方案实际上不起作用,因为
java.lang.ConditionalSpecialCasing
类中有问题的
哈希表是静态的,仍将由所有线程共享。我建议你接受西布尼克的回答,而不是我的


一个简单的解决方案是使trLoc成为一个
ThreadLocal
:将为每个线程自动创建一个新实例(根据需要)。如果您有一个线程池或类似的池,这将很好:您将只创建与池中线程数量相同的
Locale
实例,这应该是相当合理的。由于每个线程将访问不同的
语言环境实例
,因此您将不再有访问同步哈希表的争用

private ThreadLocal<Locale> trLoc = new ThreadLocal<Locale>() {
    @Override
    protected Locale initialValue() {
        return new Locale("tr", "TR");
    }
};

public double calculate(String arg1){
    arg1 = arg1.toUpperCase(trLoc.get());
    ...
}
private ThreadLocal trLoc=new ThreadLocal(){
@凌驾
受保护的区域设置初始值(){
返回新的区域设置(“tr”、“tr”);
}
};
公共双计算(字符串arg1){
arg1=arg1.toUpperCase(trLoc.get());
...
}

经过短暂的探索,JDK似乎帮不了你。我建议获取
java.lang.ConditionalSpecialCasing
类,复制它并用哈希表修复问题。您可以用
HashMap
替换
Hashtable
。我看不出有任何理由在这里使用哈希表。

基于我运行了一些基准测试的答案

  • upperCaseEN
    使用
    Local.ENGLISH
  • upperCaseTR
    使用
    新语言环境(“tr”、“tr”)
JDK 8 jdk8补丁 使用打补丁的
条件专用套管
类,使用
哈希映射
而不是
哈希表

Benchmark                              Mode  Samples     Score  Score error   Units
s.o.MyBenchmark.upperCaseTR           thrpt       25  3331.277       77.691  ops/ms
另一种解决方案是,如果字符串包含小写的
i
,则首先扫描该字符串。因为这似乎是土耳其语言环境中唯一需要对
toUpperCase
进行特殊处理的字符

if (state.lowercase.contains("i")) {
    uppercase = lowercase.toUpperCase(TR_LOCALE));
} else {
    uppercase = lowercase.toUpperCase(EN_LOCALE));
}
这已经提高了性能

Benchmark                              Mode  Samples     Score  Score error   Units
s.o.MyBenchmark.upperCasePatchedTR    thrpt       25  8753.116       51.582  ops/ms
编辑可以在


基于次优的建议,即扫描小写字母“i”,我尝试了一种位代码,将i替换为无害字符,将其替换为大写字母,并将其替换回大写字母。我不可靠的性能测试并没有显示速度有很大的提高,YMMV。请改为使用JMH测试性能,但您已经知道了这一点

然后我尝试了一种基于表格的方法。这和预期的一样快

一如既往,代码仅用于信息。勉强测试过

import java.util.*;
import java.util.concurrent.atomic.*;

public class Benchmark {
    // Substitute i Turkish toUpperCase.
    public static String toUpperCase(String str) { 
        int index = str.indexOf('i');
        if (index == -1) {
            return str.toUpperCase(tr);
        } else {
            char[] array = str.toCharArray();
            char[] localised = toUpperCase(array, index);
            return String.valueOf(localised);
        }
    }
    private static char[] toUpperCase(char[] array, int index) {
        array[index] = 'X';
        int next = indexOf('i', array, index+1);
        final char[] localised;
        if (next == -1) {
            String upper = String.valueOf(array).toUpperCase(tr);
            int len = upper.length();
            if (len == array.length) {
                localised = array;
                upper.getChars(0, len, localised, 0);
            } else {
                localised = upper.toCharArray();
            }
        } else {
            localised = toUpperCase(array, next);
        }
        localised[index] = '\u0130';
        return localised;
    }
    private static int indexOf(char c, char[] array, int off) {
        while (off<array.length && array[off] != c) {
            ++off;
        }
        return off==array.length ? -1 : off;
    }

    // Table-based Turkish toUpperCase.

    private static final int limit = 1<<9;
    private static final char[] table;
    static {
        Locale locale = new Locale("tr", "TR");
        table = new char[limit];
        char[] buff = { ' ' };
        for (int c=0; c<limit; ++c) {
            buff[0] = (char)c;
            String upper = String.valueOf(buff).toUpperCase(locale);
            if (upper.length() != 1 && c != 223 && c != 329 && c != 496) { // es zett etc
                throw new Error("do not run: "+c);
            }
            table[c] = upper.charAt(0);
        }
    }

    public static String tableToUpperCase(String str) {
        int len = str.length();
        char[] buff = new char[len];
        int i;
        for (i=0; i<len; ++i) {
            char c = str.charAt(i);
            if (c >= limit || c == 223 || c == 329 || c == 496) {
                break;
            }
            buff[i] = table[c];
        }
        return i==len ? String.valueOf(buff) : str.toUpperCase(tr);
    }

    // Ropey benchmark.

    private static final Locale tr =
        new Locale("tr", "TR");
        //Locale.ENGLISH;
    public static void main(String[] args) {
        System.err.println("friingi".toUpperCase(tr));
        System.err.println(toUpperCase("friingi"));
        int total = 0;
        for (int i=0; i<5; ++i) {
            long start = System.nanoTime();
            total += run();
            long time = System.nanoTime()-start;
            System.err.println(time/1000_000_000.0);
        }
        System.err.println(total);
    }
    private static int run() {
        AtomicInteger total = new AtomicInteger(0);
        List<Thread> threads = new ArrayList<>();
        for (int i=0; i<100; ++i) {
           threads.add(new Thread(() -> { 
               total.addAndGet(runOne());
           }));
        }
        threads.forEach(Thread::start);
        threads.forEach(thread -> {
            try {
                thread.join();
            } catch (Exception exc) {
                throw new Error(exc);
            }
         });

        return total.get();
    }
    private static int runOne() {
        int sum = 0;
        for (int i=0; i<10_000; ++i) {
            sum +=
                /**/
                tableToUpperCase("fringe")
                //toUpperCase("fringe")
                /*/
                "fringe".toUpperCase(tr)
                /**/
                .length();
        }
        return sum;
    }
}
import java.util.*;
导入java.util.concurrent.atomic.*;
公共课基准{
//代替我的土耳其图珀案。
公共静态字符串toUpperCase(字符串str){
int index=str.indexOf('i');
如果(索引==-1){
返回str.toUpperCase(tr);
}否则{
char[]数组=str.toCharArray();
char[]localised=toUpperCase(数组,索引);
返回字符串.valueOf(本地化);
}
}
私有静态char[]toUpperCase(char[]数组,int索引){
数组[索引]='X';
int next=indexOf('i',数组,索引+1);
最终字符[]本地化;
如果(下一个==-1){
字符串上限=String.valueOf(数组).toUpperCase(tr);
int len=上限.length();
if(len==array.length){
局部=阵列;
getChars(0,len,localized,0);
}否则{
Localized=upper.toCharArray();
}
}否则{
Localized=toUpperCase(数组,下一个);
}
本地化[索引]='\u0130';
返回本地;
}
私有静态int indexOf(char c,char[]数组,int off){

虽然(关闭此选项不起作用。
ConditionalSpecialCasing
仍然在内部使用相同的
Hashtable
,无论您创建了多少个
Locale
。检查代码后,看起来您肯定是对的-Hashtable是静态的,所有线程都将共享该Hashtable。我已经编辑了我的答案。我很惊讶这样一个“feature”以前没有被检测到。我在谷歌上搜索了与
条件特殊情况相关的性能问题,但什么也没有找到。它只发生在(java.lang.String)
boolean localeDependent=(lang==“tr”| lang==“az”| lang==“lt”)上
这可能值得报告—我会这样做,但我认为最好是RFE由实际遇到问题的人提交,并且可以提供一个测试用例。如果字符串包含I或ï(可能是其中的大多数),则使用错误的区域设置似乎不正确。(立陶宛人也有类似的问题,我相信还有代孕。)我想你可以把有问题的字母从非特殊的字母中移到大写,然后替换这些字母。@TomHawtin tackline这个问题是关于语言环境
tr_tr
的,对于这个问题,只有小写的
I
在转换为大写时需要特殊处理。我编辑了我的答案,使之明确。你的答案是d不同的区域设置(包括
条件特殊情况
)这需要一些修改。(我尝试过用“我不在”。即使在我2014年的MacBook Air(主板从2019年开始…)上有线程,性能也只有一点改进。)@TomHawtin tackline I a
import java.util.*;
import java.util.concurrent.atomic.*;

public class Benchmark {
    // Substitute i Turkish toUpperCase.
    public static String toUpperCase(String str) { 
        int index = str.indexOf('i');
        if (index == -1) {
            return str.toUpperCase(tr);
        } else {
            char[] array = str.toCharArray();
            char[] localised = toUpperCase(array, index);
            return String.valueOf(localised);
        }
    }
    private static char[] toUpperCase(char[] array, int index) {
        array[index] = 'X';
        int next = indexOf('i', array, index+1);
        final char[] localised;
        if (next == -1) {
            String upper = String.valueOf(array).toUpperCase(tr);
            int len = upper.length();
            if (len == array.length) {
                localised = array;
                upper.getChars(0, len, localised, 0);
            } else {
                localised = upper.toCharArray();
            }
        } else {
            localised = toUpperCase(array, next);
        }
        localised[index] = '\u0130';
        return localised;
    }
    private static int indexOf(char c, char[] array, int off) {
        while (off<array.length && array[off] != c) {
            ++off;
        }
        return off==array.length ? -1 : off;
    }

    // Table-based Turkish toUpperCase.

    private static final int limit = 1<<9;
    private static final char[] table;
    static {
        Locale locale = new Locale("tr", "TR");
        table = new char[limit];
        char[] buff = { ' ' };
        for (int c=0; c<limit; ++c) {
            buff[0] = (char)c;
            String upper = String.valueOf(buff).toUpperCase(locale);
            if (upper.length() != 1 && c != 223 && c != 329 && c != 496) { // es zett etc
                throw new Error("do not run: "+c);
            }
            table[c] = upper.charAt(0);
        }
    }

    public static String tableToUpperCase(String str) {
        int len = str.length();
        char[] buff = new char[len];
        int i;
        for (i=0; i<len; ++i) {
            char c = str.charAt(i);
            if (c >= limit || c == 223 || c == 329 || c == 496) {
                break;
            }
            buff[i] = table[c];
        }
        return i==len ? String.valueOf(buff) : str.toUpperCase(tr);
    }

    // Ropey benchmark.

    private static final Locale tr =
        new Locale("tr", "TR");
        //Locale.ENGLISH;
    public static void main(String[] args) {
        System.err.println("friingi".toUpperCase(tr));
        System.err.println(toUpperCase("friingi"));
        int total = 0;
        for (int i=0; i<5; ++i) {
            long start = System.nanoTime();
            total += run();
            long time = System.nanoTime()-start;
            System.err.println(time/1000_000_000.0);
        }
        System.err.println(total);
    }
    private static int run() {
        AtomicInteger total = new AtomicInteger(0);
        List<Thread> threads = new ArrayList<>();
        for (int i=0; i<100; ++i) {
           threads.add(new Thread(() -> { 
               total.addAndGet(runOne());
           }));
        }
        threads.forEach(Thread::start);
        threads.forEach(thread -> {
            try {
                thread.join();
            } catch (Exception exc) {
                throw new Error(exc);
            }
         });

        return total.get();
    }
    private static int runOne() {
        int sum = 0;
        for (int i=0; i<10_000; ++i) {
            sum +=
                /**/
                tableToUpperCase("fringe")
                //toUpperCase("fringe")
                /*/
                "fringe".toUpperCase(tr)
                /**/
                .length();
        }
        return sum;
    }
}