Являются ли статические вызовы Java более или менее дорогими, чем нестатические вызовы?

Есть ли какое-то преимущество в производительности, так или иначе? Это специфично для компилятора/VM? Я использую точку доступа.


person Andy Faibishenko    schedule 27.09.2010    source источник


Ответы (12)


Во-первых: вы не должны делать выбор между статическим и нестатическим на основе производительности.

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

В-третьих: большая часть мифов о статике и нестатичности основана либо на очень старых JVM (которые не делали и близкой оптимизации, которую делает Hotspot), либо на некоторых запомнившихся мелочах о C++ (в которых динамический вызов использует один больший доступ к памяти, чем статический вызов).

person Anon    schedule 27.09.2010
comment
@AaronDigulla Я полагаю, вы имеете в виду, что статические методы не очень хорошо подходят для тестируемой базы кода? - person H.Rabiee; 29.05.2015
comment
@хайдер: Да. PowerMock может это сделать, но за это приходится платить. - person Aaron Digulla; 29.05.2015
comment
Вы абсолютно правы, вы не должны отдавать предпочтение статическим методам, основанным только на этом. Однако в случае, если статические методы хорошо подходят для проекта, полезно знать, что они по крайней мере так же быстры, если не быстрее, чем методы экземпляра, и их не следует исключать из соображений производительности. - person Will; 21.10.2017
comment
@AaronDigulla -.- что, если я скажу вам, что пришел сюда, потому что оптимизирую прямо сейчас, не преждевременно, а когда мне это действительно нужно? Вы предположили, что OP хочет преждевременно оптимизировать, но вы знаете, что этот сайт в некотором роде глобальный ... Верно? Я не хочу показаться грубым, но, пожалуйста, в следующий раз не предполагай ничего подобного. - person Dalibor Filus; 01.11.2017
comment
@DaliborFilus Мне нужно найти баланс. Использование статических методов вызывает всевозможные проблемы, поэтому их следует избегать, особенно если вы не знаете, что делаете. Во-вторых, самый медленный код возникает из-за (плохого) дизайна, а не из-за медленного выбора языка. Если ваш код работает медленно, статические методы, скорее всего, не спасут его, если только не вызовут методы, которые абсолютно ничего не делают. В большинстве случаев код в методов затмит накладные расходы на вызов. - person Aaron Digulla; 06.11.2017
comment
Проголосовали против. Это не отвечает на вопрос. Вопрос задан о преимуществах производительности. Он не спрашивал мнения о принципах проектирования. - person Colm Bhandal; 29.06.2018
comment
Если бы я научил попугая говорить, что преждевременная оптимизация — корень всех зол, я бы получил 1000 голосов от людей, которые знают о производительности не меньше, чем попугай. - person rghome; 28.01.2019

Четыре года спустя...

Хорошо, в надежде решить этот вопрос раз и навсегда, я написал тест, который показывает, как различные виды вызовов (виртуальные, невиртуальные, статические) сравниваются друг с другом.

Я запустил его в ideone и вот что получил:

(Чем больше повторений, тем лучше.)

    Success time: 3.12 memory: 320576 signal:0
  Name          |  Iterations
    VirtualTest |  128009996
 NonVirtualTest |  301765679
     StaticTest |  352298601
Done.

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

Чего я не ожидал, так это того, что различия будут столь заметными: было измерено, что вызовы виртуальных методов выполняются со скоростью менее половины скорости вызовов невиртуальных методов, которые, в свою очередь, выполнялись в целом < strong>на 15 % медленнее, чем статические вызовы. Вот что показывают эти измерения; фактические различия должны быть на самом деле немного более выраженными, поскольку для каждого вызова виртуального, невиртуального и статического метода мой тестовый код имеет дополнительные постоянные накладные расходы на увеличение одной целочисленной переменной, проверку логической переменной и зацикливание, если оно не истинно.

Я предполагаю, что результаты будут варьироваться от ЦП к ЦП и от JVM к JVM, поэтому попробуйте и посмотрите, что вы получите:

import java.io.*;

class StaticVsInstanceBenchmark
{
    public static void main( String[] args ) throws Exception
    {
        StaticVsInstanceBenchmark program = new StaticVsInstanceBenchmark();
        program.run();
    }

    static final int DURATION = 1000;

    public void run() throws Exception
    {
        doBenchmark( new VirtualTest( new ClassWithVirtualMethod() ), 
                     new NonVirtualTest( new ClassWithNonVirtualMethod() ), 
                     new StaticTest() );
    }

    void doBenchmark( Test... tests ) throws Exception
    {
        System.out.println( "  Name          |  Iterations" );
        doBenchmark2( devNull, 1, tests ); //warmup
        doBenchmark2( System.out, DURATION, tests );
        System.out.println( "Done." );
    }

    void doBenchmark2( PrintStream printStream, int duration, Test[] tests ) throws Exception
    {
        for( Test test : tests )
        {
            long iterations = runTest( duration, test );
            printStream.printf( "%15s | %10d\n", test.getClass().getSimpleName(), iterations );
        }
    }

    long runTest( int duration, Test test ) throws Exception
    {
        test.terminate = false;
        test.count = 0;
        Thread thread = new Thread( test );
        thread.start();
        Thread.sleep( duration );
        test.terminate = true;
        thread.join();
        return test.count;
    }

    static abstract class Test implements Runnable
    {
        boolean terminate = false;
        long count = 0;
    }

    static class ClassWithStaticStuff
    {
        static int staticDummy;
        static void staticMethod() { staticDummy++; }
    }

    static class StaticTest extends Test
    {
        @Override
        public void run()
        {
            for( count = 0;  !terminate;  count++ )
            {
                ClassWithStaticStuff.staticMethod();
            }
        }
    }

    static class ClassWithVirtualMethod implements Runnable
    {
        int instanceDummy;
        @Override public void run() { instanceDummy++; }
    }

    static class VirtualTest extends Test
    {
        final Runnable runnable;

        VirtualTest( Runnable runnable )
        {
            this.runnable = runnable;
        }

        @Override
        public void run()
        {
            for( count = 0;  !terminate;  count++ )
            {
                runnable.run();
            }
        }
    }

    static class ClassWithNonVirtualMethod
    {
        int instanceDummy;
        final void nonVirtualMethod() { instanceDummy++; }
    }

    static class NonVirtualTest extends Test
    {
        final ClassWithNonVirtualMethod objectWithNonVirtualMethod;

        NonVirtualTest( ClassWithNonVirtualMethod objectWithNonVirtualMethod )
        {
            this.objectWithNonVirtualMethod = objectWithNonVirtualMethod;
        }

        @Override
        public void run()
        {
            for( count = 0;  !terminate;  count++ )
            {
                objectWithNonVirtualMethod.nonVirtualMethod();
            }
        }
    }

    static final PrintStream devNull = new PrintStream( new OutputStream() 
    {
        public void write(int b) {}
    } );
}

Стоит отметить, что эта разница в производительности применима только к коду, который не делает ничего, кроме вызова методов без параметров. Любой другой код, который у вас есть между вызовами, сгладит различия, включая передачу параметров. На самом деле разница в 15% между статическими и не виртуальными вызовами, вероятно, объясняется полностью тем, что в статический метод не нужно передавать указатель this. Таким образом, потребовалось бы совсем небольшое количество кода, выполняющего тривиальные действия между вызовами, чтобы разница между различными типами вызовов была размыта до такой степени, что не имела бы никакого общего влияния.

Кроме того, не просто так существуют вызовы виртуальных методов; у них действительно есть цель, и они реализованы с использованием наиболее эффективных средств, предоставляемых базовым оборудованием. (Набор инструкций ЦП.) Если в вашем желании избавиться от них, заменив их невиртуальными или статическими вызовами, вам в конечном итоге придется добавить хоть йоту дополнительного кода для эмуляции их функциональности, то ваши результирующие чистые накладные расходы ограничены. быть не меньше, а больше. Вполне возможно, намного, намного, непостижимо намного, больше.

person Mike Nakis    schedule 14.02.2015
comment
«Виртуальный» — это термин C++. В Java нет виртуальных методов. Существуют обычные методы, которые являются полиморфными во время выполнения, и статические или окончательные методы, которые таковыми не являются. - person Zhenya; 05.03.2015
comment
@levgen да, для того, чья точка зрения столь же узка, как официальный высокоуровневый обзор языка, все именно так, как вы говорите. Но, конечно же, высокоуровневые концепции реализуются с использованием хорошо зарекомендовавших себя низкоуровневых механизмов, которые были изобретены задолго до появления Java, и виртуальные методы являются одним из них. Если вы хоть немного заглянете под капот, то сразу увидите, что это так: docs.oracle.com/javase/specs/jvms/se7/html/ - person Mike Nakis; 05.03.2015
comment
Спасибо за ответ на вопрос, не делая предположений о преждевременной оптимизации. Отличный ответ. - person vegemite4me; 19.01.2016
comment
Большой разрыв между виртуальным звонком и невиртуальным звонком заставляет задуматься. Я ожидаю, что производительность будет почти такой же в вашем тесте. Поскольку поле, содержащее Runnable, является окончательным, не должно быть причин разрешать виртуальный метод более одного раза. Или я что-то упускаю? - person Marten; 14.09.2016
comment
@Marten Я не знаю, есть ли механизм разрешения виртуальных методов. Без JIT-трюков любое такое разрешение обязательно будет менее эффективным, чем простой поиск, которым на самом деле является вызов виртуального метода. Если вы имеете в виду возможность того, что JIT может обнаружить, что вызов всегда идет к одной и той же цели, и заменить виртуальный вызов невиртуальным вызовом, есть две возможности: а) компиляторы JIT не такие умные б) не было JITting в моих бенчмарках. Не стесняйтесь попробовать сами, код, который я разместил, является самодостаточным и работоспособным. - person Mike Nakis; 14.09.2016
comment
Да, именно это я и имел в виду. Во всяком случае, я только что провел тест на своей машине. Помимо дрожания, которое вы можете ожидать от такого теста, нет никакой разницы в скорости: VirtualTest | 488846733 -- NonVirtualTest | 480530022 -- StaticTest | 484353198 на моей установке OpenJDK. FTR: Это верно, даже если я уберу модификатор final. Кстати. Пришлось сделать поле terminate volatile, иначе тест не закончился. - person Marten; 17.09.2016
comment
Это все очень странно. За исключением необходимости сделать поле завершения нестабильным. Я ожидал, что он должен быть изменчивым, но по какой-то причине он работал у меня без изменчивости, поэтому я оставил его таким. Тот факт, что он должен был быть изменчивым, чтобы работать на вас, вероятно, означает, что у вас включено больше оптимизаций. Но тогда я не понимаю ваших результатов. странно. - person Mike Nakis; 17.09.2016
comment
К вашему сведению, я получаю довольно неожиданные результаты на Nexus 5 под управлением Android 6: VirtualTest | 12451872 -- NonVirtualTest | 12089542 -- StaticTest | 8181170. Мало того, что OpenJDK на моем ноутбуке выполняет в 40 раз больше итераций, статический тест всегда имеет примерно на 30% меньшую пропускную способность. Это может быть специфическим феноменом ART, потому что я получаю ожидаемый результат на планшете с Android 4.4: VirtualTest | 138183740 -- NonVirtualTest | 142268636 -- StaticTest | 161388933 - person Marten; 17.09.2016
comment
Я только что заметил, что номера Android 4.4 неверны. На самом деле это VirtualTest | 13818374 -- NonVirtualTest | 14226863 -- StaticTest | 16138893, так что только 10% исходных чисел. Я увеличил DURATION в 10 раз, прежде чем запускать этот тест. Все еще не медленнее, чем Nexus 5, что странно. - person Marten; 17.09.2016
comment
FWIW, я только что запустил его на i7 2,6 ГГц и получил следующее: VirtualTest | 510795847 -- NonVirtualTest | 539244268 -- Статический тест | 554098864, что больше соответствует числам, которые вы получаете. Цифры, которые я разместил в ответе, взяты с ideone.com. Возможно, кэш процессора ideone.com перегружен из-за чрезмерной загрузки. - person Mike Nakis; 17.09.2016
comment
@Marten, а вот результаты моего i7-4790K с частотой 4 ГГц: VirtualTest = 542M; NonVirtualTest = 607M; StaticTest = 684M - person Mike Nakis; 11.10.2016
comment
Это была отладка. Без отладки результаты следующие: VirtualTest = 631M; NonVirtualTest = 629M; StaticTest = 689M. (Таким образом, нет разницы между виртуальным и невиртуальным и менее выраженной разницы между теми и статическими.) - person Mike Nakis; 11.10.2016
comment
Спасибо, что показали эталонные цифры! Я нахожу результаты здесь интересными, особенно потому, что в Intellij есть опция проверки кода, которая проверяет, можно ли объявить метод статическим без изменения кода. - person Alexander Oh; 14.02.2017
comment
Причина, по которой этот тест может завершиться без объявления terminate как volatile в некоторых средах, заключается в том, что он выполняется в холодном состоянии, т. е. затем интерпретируется, что делает весь «тест» спорным. На практике любое место кода, критичное для производительности, будет оптимизировано, что не только устранит накладные расходы на вызов метода, но и избыточное чтение энергонезависимой переменной. В моей системе воспроизводимые зависания даже без прогрева. Конечно, добавление к флагу модификатора volatile сделало бы и весь тест бесполезным. Сделать осмысленный микротест не так уж и просто. - person Holger; 28.01.2019
comment
@Holger Я не сомневаюсь в том, что ты говоришь. Любой эталон такого рода обязательно будет весьма неточным. Но я думаю, что это дает достойный показатель. И точность можно считать не такой уж плохой, если учесть, что производственный код почти так же вероятно будет работать в холодном состоянии, как и этот тест. - person Mike Nakis; 28.01.2019

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

Тем не менее, это не должно влиять на ваш дизайн — код должен быть максимально читабельным и естественным образом — и беспокоиться о такого рода микрооптимизации можно только в том случае, если у вас есть веская причина (чего вы почти никогда не будете).

person Jon Skeet    schedule 27.09.2010
comment
Возможные причины, по которым статический вызов может быть быстрее Не могли бы вы объяснить мне эти причины? - person JavaTechnical; 20.07.2013
comment
@JavaTechnical: ответ объясняет эти причины - нет переопределения (что означает, что вам не нужно разрабатывать реализацию для использования каждый раз, когда и вы можете встроить), и вам не нужно проверять, действительно ли вы вызываете метод для нулевой ссылки. - person Jon Skeet; 20.07.2013
comment
@JavaTechnical: я не понимаю. Я только что дал вам вещи, которые не нужно вычислять/проверять для статических методов, а также возможность встраивания. Отсутствие работы является преимуществом в производительности. Что осталось понять? - person Jon Skeet; 20.07.2013
comment
Статические переменные извлекаются быстрее, чем нестатические? - person JavaTechnical; 20.07.2013
comment
@JavaTechnical: Ну, нет необходимости выполнять проверку на недействительность, но если JIT-компилятор может удалить эту проверку (которая будет зависеть от контекста), я не ожидаю большой разницы. Такие вещи, как наличие памяти в кеше, были бы гораздо важнее. - person Jon Skeet; 20.07.2013
comment
давайте продолжим это обсуждение в чате - person JavaTechnical; 20.07.2013

Это зависит от компилятора/VM.

  • Теоретически статический вызов можно сделать несколько более эффективным, поскольку ему не нужно выполнять поиск виртуальной функции, а также можно избежать накладных расходов, связанных со скрытым параметром this.
  • На практике многие компиляторы все равно оптимизируют это.

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

Однако я увидел, что эта оптимизация значительно повысила производительность в следующей ситуации:

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

Если вышесказанное относится к вам, возможно, стоит проверить.

Есть еще одна веская (и потенциально даже более важная!) причина для использования статического метода - если метод на самом деле имеет статическую семантику (т.е. логически не связан с данным экземпляром класса), то имеет смысл сделать его статическим отразить этот факт. Опытные Java-программисты заметят модификатор static и сразу же подумают: «Ага! Этот метод статический, поэтому ему не нужен экземпляр и, по-видимому, он не манипулирует конкретным состоянием экземпляра». Таким образом, вы эффективно сообщили о статической природе метода....

person mikera    schedule 27.09.2010

7 лет спустя...

У меня нет большого доверия к результатам, полученным Майком Накисом, потому что они не решают некоторые распространенные проблемы, связанные с оптимизацией Hotspot. Я провел контрольные тесты с использованием JMH и обнаружил, что накладные расходы метода экземпляра на моей машине составляют около 0,75% по сравнению со статическим вызовом. Учитывая эти низкие накладные расходы, я думаю, за исключением наиболее чувствительных к задержкам операций, это, возможно, не самая большая проблема при разработке приложений. Сводные результаты моего теста JMH следующие:

java -jar target/benchmark.jar

# -- snip --

Benchmark                        Mode  Cnt          Score         Error  Units
MyBenchmark.testInstanceMethod  thrpt  200  414036562.933 ± 2198178.163  ops/s
MyBenchmark.testStaticMethod    thrpt  200  417194553.496 ± 1055872.594  ops/s

Вы можете посмотреть код здесь, на Github;

https://github.com/nfisher/svsi

Сам по себе тест довольно прост, но направлен на минимизацию устранения мертвого кода и сворачивания констант. Возможно, есть и другие оптимизации, которые я пропустил/упустил из виду, и эти результаты, вероятно, будут различаться в зависимости от версии JVM и ОС.

package ca.junctionbox.svsi;

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.infra.Blackhole;

class InstanceSum {
    public int sum(final int a, final int b) {
        return a + b;
    }
}

class StaticSum {
    public static int sum(final int a, final int b) {
        return a + b;
    }
}

public class MyBenchmark {
    private static final InstanceSum impl = new InstanceSum();

    @State(Scope.Thread)
    public static class Input {
        public int a = 1;
        public int b = 2;
    }

    @Benchmark
    public void testStaticMethod(Input i, Blackhole blackhole) {
        int sum = StaticSum.sum(i.a, i.b);
        blackhole.consume(sum);
    }

    @Benchmark
    public void testInstanceMethod(Input i, Blackhole blackhole) {
        int sum = impl.sum(i.a, i.b);
        blackhole.consume(sum);
    }
}
person Nathan    schedule 26.12.2017
comment
Здесь чисто академический интерес. Мне любопытны любые потенциальные преимущества такого рода микрооптимизации для показателей, отличных от ops/s, прежде всего в среде ART (например, использование памяти, уменьшенный размер файла .oat и т. д.). Знаете ли вы какие-либо относительно простые инструменты/способы, с помощью которых можно было бы попытаться сравнить эти другие показатели? - person Ryan Thomas; 05.10.2019
comment
Hotspot выясняет, что в пути к классам нет расширений для InstanceSum. Попробуйте добавить другой класс, расширяющий InstanceSum и переопределяющий метод. - person milan; 18.02.2020

Как уже говорилось в предыдущих постах: это похоже на преждевременную оптимизацию.

Однако есть одно отличие (частично из-за того, что нестатические вызовы требуют дополнительного помещения вызываемого объекта в стек операндов):

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

Разница на уровне байт-кода заключается в том, что вызов нестатического метода выполняется через INVOKEVIRTUAL, INVOKEINTERFACE или INVOKESPECIAL, в то время как вызов статического метода выполняется через INVOKESTATIC.

person aioobe    schedule 27.09.2010
comment
Однако метод частного экземпляра (по крайней мере, обычно) вызывается с использованием invokespecial, поскольку он не является виртуальным. - person Mark Peters; 27.09.2010
comment
А, интересно, я мог думать только о конструкторах, поэтому и пропустил! Спасибо! (обновление ответа) - person aioobe; 27.09.2010
comment
JVM будет оптимизировать, если будет создан экземпляр одного типа. Если B расширяет A, и ни один экземпляр B не был создан, вызовы методов для A не потребуют поиска в виртуальной таблице. - person Steve Kuo; 27.09.2010

Невероятно маловероятно, что какая-либо разница в производительности статических и нестатических вызовов влияет на ваше приложение. Помните, что «преждевременная оптимизация — корень всех зол».

person DJClayworth    schedule 27.09.2010
comment
Это был Кнут! shreevatsa.wordpress.com /2008/05/16/ - person ShreevatsaR; 27.09.2010
comment
не могли бы вы дополнительно объяснить, что преждевременная оптимизация является корнем всех зол.? - person user2121; 22.11.2016
comment
Вопрос был в том, есть ли какое-то преимущество в производительности, и это точно отвечает на этот вопрос. - person DJClayworth; 28.01.2019

Для решения, должен ли метод быть статическим, аспект производительности не должен иметь значения. Если у вас есть проблемы с производительностью, то статическое множество методов не спасет ситуацию. Тем не менее, статические методы почти наверняка не медленнее, чем любой метод экземпляра, в большинстве случаев немного быстрее:

1.) Статические методы не полиморфны, поэтому у JVM меньше решений, чтобы найти фактический код для выполнения. Это спорный вопрос в эпоху Hotspot, поскольку Hotspot будет оптимизировать вызовы методов экземпляра, которые имеют только один сайт реализации, поэтому они будут работать одинаково.

2.) Еще одно тонкое отличие состоит в том, что статические методы явно не имеют ссылки на this. Это приводит к тому, что кадр стека на один слот меньше, чем у метода экземпляра с той же сигнатурой и телом («это» помещается в слот 0 локальных переменных на уровне байт-кода, тогда как для статических методов слот 0 используется для первого параметр метода).

person Durandal    schedule 27.09.2010

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

Это определенно часть 97 % небольших преимуществ, о которых вам следует забыть.

person Michael Borgwardt    schedule 27.09.2010
comment
Неправильный. Вы не можете ничего предполагать. Это может быть тесная петля, необходимая для пользовательского интерфейса переднего плана, что может иметь огромное значение для того, насколько быстрым будет пользовательский интерфейс. Например, поиск в TableView миллионов записей. - person trilogy; 05.12.2018

Теоретически дешевле.

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

Однако я не проверял это.

person Powerlord    schedule 27.09.2010
comment
@Р. Бемроуз, какое отношение к этому вопросу имеет статическая инициализация? - person Kirk Woll; 27.09.2010
comment
@Kirk Woll: Поскольку статическая инициализация выполняется при первом обращении к классу ... в том числе до первого вызова статического метода. - person Powerlord; 27.09.2010
comment
@Р. Bemrose, конечно, как и загрузка класса в виртуальную машину для начала. Похоже на несекквитор, ИМО. - person Kirk Woll; 27.09.2010

Как отмечает Джон, статические методы нельзя переопределить, поэтому простой вызов статического метода может оказаться — в достаточно наивной среде выполнения Java — быстрее, чем вызов метода экземпляра. .

Но тогда, даже если предположить, что вы находитесь в той точке, когда вы заботитесь о том, чтобы испортить свой дизайн, чтобы сэкономить несколько наносекунд, возникает еще один вопрос: нужно ли вам переопределять метод? Если вы измените свой код, чтобы превратить метод экземпляра в статический метод, чтобы сэкономить наносекунду здесь и там, а затем развернетесь и реализуете свой собственный диспетчер поверх этого, ваш почти наверняка будет менее эффективным, чем созданный уже в среду выполнения Java.

person Ken    schedule 27.09.2010

Я хотел бы добавить к другим замечательным ответам здесь, что это также зависит от вашего потока, например:

Public class MyDao {

   private String sql = "select * from MY_ITEM";

   public List<MyItem> getAllItems() {
       springJdbcTemplate.query(sql, new MyRowMapper());
   };
};

Обратите внимание, что вы создаете новый объект MyRowMapper для каждого вызова.
Вместо этого я предлагаю использовать здесь статическое поле.

Public class MyDao {

   private static RowMapper myRowMapper = new MyRowMapper();
   private String sql = "select * from MY_ITEM";

   public List<MyItem> getAllItems() {
       springJdbcTemplate.query(sql, myRowMapper);
   };
};
person Yair Zaslavsky    schedule 10.07.2015