Преимущество использования статических переменных в Java - PullRequest
3 голосов
/ 29 сентября 2010

Скажем, у меня есть два класса, как это:

class A{  
    private static Random random = new Random();  

    public A(){  
        // Do something.
    }

    public Integer methodGetsCalledQuiteOften(){
        return random.nextInt();
    }
}

class B{  
     private Random random;  

     public A(){  
         random = new Random();
         // Do something.
     }

     public Integer methodGetsCalledQuiteOften(){
         return random.nextInt();
     }
}

В сценарии, когда оба экземпляра создаются несколько раз, а метод экземпляров этих классов methodGetsCalledQuiteOften вызывается много раз, есть ли какие-либо реальные преимущества / недостатки (время, память) использование статической переменной, которая содержит Random() в классе A, в отличие от создания нового объекта Random() в каждом отдельном экземпляре, как в классе B?

Приложение является многопоточным и имеет более высокий уровень случайности, поэтому я думаю, что я использую статический SecureRandom. Если после профилирования это будет реальный фактор скорости, я мог бы выбрать что-то другое.

Ответы [ 10 ]

6 голосов
/ 29 сентября 2010

Реальный преимущества / недостатки зависят от реального кода. Другими словами, это зависит от того, как часто создается B по сравнению с тем, как часто вызывается метод и т. Д. Вам следует профилировать приложение и посмотреть, имеет ли оно разумное значение.

Будет ли А более производительным, чем Б? Конечно. Но то, заметите ли вы когда-нибудь, зависит от вашего использования. Будет ли A использовать меньше памяти, чем B? Конечно, но все равно, заботишься ты о себе или нет, зависит от того, сколько экземпляров A / B ты держишь рядом.

Действительно, единственным другим соображением является детерминизм. Поскольку вы не указываете начальное число для экземпляра Random, я так понимаю, вам все равно, сможете ли вы воспроизвести последовательность чисел из Random. Но стоит отметить ... если у вас есть общий случайный случай, будет намного сложнее гарантировать определенную детерминированную последовательность чисел для некоторого экземпляра A, чем для одного для экземпляра, как в B.

5 голосов
/ 29 сентября 2010

Просто скажи нет изменяемой статике, ладно.

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

Создание нового экземпляра каждый раз кажется расточительным.Хотя, конечно, не оптимизируйте преждевременно (если бы вы оптимизировали, вы бы не использовали java.util.Random).Первоначальное увеличение может также вызвать проблемы.

Наилучший подход - передать экземпляр («Параметр сверху» или «Правильное использование конструкторов»).Затем вы можете тестировать, воспроизводить, макетировать и т. Д. Вы работоспособны и можете переключиться в другую реализацию.

3 голосов
/ 29 сентября 2010

Если ваша программа однопоточная, ваш Random должен быть членом класса (static).Это немного эффективнее.Это даже более важно при использовании SecureRandom, который может занять относительно длительное время для начального заполнения.

Если несколько потоков в итоге вызовут methodGetsCalledQuiteOften(), проблема немного сложнее.Класс является поточно-ориентированным, но издержки, необходимые для защиты его состояния во время одновременных изменений, могут быть сопоставимы с созданием новых независимых экземпляров Random.

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

2 голосов
/ 29 сентября 2010

Хотя создание экземпляра класса A значительно (в 10 раз) быстрее, чем класса B, это имеет значение только в том случае, если вы делаете это примерно 100 000 раз в секунду.

Что касается безопасности потоков, я понимаю, что .nextInt () основан на .next () , который должен быть безопасным для потоков. Так что многопоточность здесь не должна создавать проблем.

Но что более важно, поведение обоих классов может быть различным. Экземпляры класса A будут давать каждому несколько случайную последовательность чисел, но экземпляры класса B могут давать одну и ту же последовательность «случайных» чисел (это поведение может быть различным на разных платформах!). Спецификация Javadoc гласит:

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

Таким образом, если случайность важна, вы можете рассмотреть возможность предоставления уникального начального числа конструктору Random или лучше реализовать Random с более медленным java.security.SecureRandom .

2 голосов
/ 29 сентября 2010

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

private final static int SOME_CONSTANT=1;

является примером.

public class USA {
    private final static Map statesOfTheUnion = new HashMap();
    // etc
}

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

1 голос
/ 29 сентября 2010

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

1 голос
/ 29 сентября 2010

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

И поскольку его состояние включает в себя один AtomicLong объект (8 байт), это не большая трата памяти (если только вы не планируете создать огромный количество B экземпляров).

Так что, я бы сказал, есть небольшая разница в любом случае.

1 голос
/ 29 сентября 2010

доступ к статическим ресурсам не является потокобезопасным.В многопоточной среде вы можете получить странные / непредсказуемые результаты.

0 голосов
/ 09 ноября 2015

Преимущества статических переменных (основные моменты):

  1. Константы могут быть определены без использования дополнительной памяти (по одной на каждый класс).

  2. Константы могут быть доступны без создания экземпляра класса.

Преимущества статических методов:

Поведение, не зависящее от экземпляра, можно определить, не опасаясь случайного взаимодействия с экземпляром.класса.

0 голосов
/ 29 сентября 2010

С точки зрения времени и памяти я не могу думать о каких-либо больших преимуществах (статическая переменная будет частью определения класса, а не в куче). Однако статические переменные полезны, когда вы знаете, что к объекту будут обращаться из разных мест. hvgotcodes прав, хотя использование статических ресурсов не является потокобезопасным. Но если вы только читаете статическое значение, тогда используйте потоки для него.

Это избавит вас от необходимости передавать ссылки на инициируемый объект (A или B) в другой объект для использования random

...