Как бэкэнд-разработчик Java, большая часть кода, который мы пишем, определяет взаимодействие с пользователем. Если наш внутренний код не работает должным образом, пользователи будут тратить некоторое время на ожидание ответа от сервера при посещении нашего веб-сайта. Это может привести к жалобам пользователей или даже потере пользователей.
Про оптимизацию производительности большая тема. В разделе «Оптимизация производительности программы Java» говорится, что оптимизация производительности включает пять уровней: настройка дизайна, настройка кода, настройка JVM, настройка базы данных и настройка операционной системы. И каждый уровень содержит множество методологий и лучших практик. В этой статье не ставится задача дать их широкий обзор. Просто процитирую несколько часто используемых решений для оптимизации Java-кода: читатели могут по-настоящему практиковать решения в своем собственном коде после прочтения.
использовать синглтон
Для некоторых операций, которые потребляют системные ресурсы, таких как обработка ввода-вывода, подключение к базе данных, анализ и загрузка файла конфигурации, мы должны ограничить создание этих экземпляров или всегда использовать общий экземпляр для экономии системных накладных расходов.В этом случае необходимо использовать шаблон синглтона.
Синтаксический режим имеет много вариантов синтаксиса, и мой официальный аккаунт также публиковал множество статей иСтатьи, связанные с синглтоном
Использовать режим будущего
Предполагая, что задача требует некоторого времени для выполнения, чтобы сэкономить ненужное время ожидания, вы можете сначала получить «коносамент», то есть Будущее, а затем продолжить обработку других задач, пока не прибудет «товар», то есть , результат получается после выполнения задачи. , в это время можно использовать "Коносамент" для забора товара, то есть получить возвращаемое значение через объект Future.
public class RealData implements Callable<String> {
protected String data;
public RealData(String data) {
this.data = data;
}
@Override
public String call() throws Exception {
//利用sleep方法来表示真是业务是非常缓慢的
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return data;
}
}
public class Application {
public static void main(String[] args) throws Exception {
FutureTask<String> futureTask =
new FutureTask<String>(new RealData("name"));
ExecutorService executor =
Executors.newFixedThreadPool(1); //使用线程池
//执行FutureTask,相当于上例中的client.request("name")发送请求
executor.submit(futureTask);
//这里可以用一个sleep代替对其他业务逻辑的处理
//在处理这些业务逻辑过程中,RealData也正在创建,从而充分了利用等待时间
Thread.sleep(2000);
//使用真实数据
//如果call()没有执行完成依然会等待
System.out.println("数据=" + futureTask.get());
}
}
Использовать пул потоков
Правильное использование пулов потоков может принести три преимущества. Первое: снизить потребление ресурсов. Сократите стоимость создания и уничтожения потоков за счет повторного использования уже созданных потоков. Второе: улучшить скорость отклика. При поступлении задачи ее можно выполнить немедленно, не дожидаясь создания потока. Третье: улучшить управляемость потоков. Потоки - это дефицитные ресурсы. Если они создаются без ограничений, это не только потребляет системные ресурсы, но и снижает стабильность системы. Использование пулов потоков можно использовать для унифицированного распределения, настройки и мониторинга.
После Java 5 параллельное программирование представило множество новых API для запуска, планирования и управления потоками. Инфраструктура Executor была представлена в Java 5. Она использует внутренний механизм пула потоков. Он находится в пакете java.util.cocurrent. Фреймворк управляет запуском, выполнением и завершением потоков, что может упростить работу параллельного программирования.
public class MultiThreadTest {
public static void main(String[] args) {
ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("thread-%d").build();
ExecutorService executor = new ThreadPoolExecutor(2, 5, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory);
executor.execute(new Runnable() {
@Override
public void run() {
System.out.println("hello world !");
}
});
System.out.println(" ===> main Thread! " );
}
}
Использование НИО
Начиная с версии 1.4, JDK предоставляет новую библиотеку классов программирования ввода-вывода, называемую NIO, которая не только вводит новый и эффективный буфер и канал, но также представляет механизм неблокирующего ввода-вывода на основе селектора, который объединяет несколько асинхронных Операции ввода-вывода/вывода централизованы в одном или нескольких потоках для обработки.Использование NIO вместо блокировки ввода-вывода может повысить параллельную пропускную способность программы и снизить нагрузку на систему.
Для каждого запроса, если для соответствующей логической обработки открывается отдельный поток, когда передача данных клиента осуществляется не всегда, а прерывисто, соответствующий поток должен ожидать ввода-вывода и выполнять переключение контекста. После использования механизма Selector, представленного NIO, эффективность параллелизма программы может быть улучшена, и эта ситуация может быть улучшена.
public class NioTest {
static public void main( String args[] ) throws Exception {
FileInputStream fin = new FileInputStream("c:\\test.txt");
// 获取通道
FileChannel fc = fin.getChannel();
// 创建缓冲区
ByteBuffer buffer = ByteBuffer.allocate(1024);
// 读取数据到缓冲区
fc.read(buffer);
buffer.flip();
while (buffer.remaining()>0) {
byte b = buffer.get();
System.out.print(((char)b));
}
fin.close();
}
}
оптимизация блокировки
В параллельных сценариях в нашем коде часто используются блокировки. Если есть блокировки, должна быть конкуренция за блокировки, а если есть конкуренция за блокировки, будет потребляться много ресурсов. Итак, как оптимизировать блокировки в нашем Java-коде? В основном из следующих аспектов:
- Сокращение времени удержания блокировки
- Вместо синхронизированных методов можно использовать синхронизированные блоки кода. Это сокращает время удерживания блокировки.
- Уменьшить детализацию блокировки
- При использовании Map в параллельных сценариях не забудьте использовать ConcurrentHashMap вместо HashTable и HashMap.
- разделение замка
- Обычные блокировки (например, синхронизированные) заставят чтение блокировать запись, а запись также блокирует чтение. В то же время чтение, чтение и запись также будут блокироваться. Вы можете найти способы разделить операции чтения и записи.
- замок огрубление
- В некоторых случаях мы хотим объединить множество запросов на блокировку в один запрос, чтобы уменьшить потерю производительности, вызванную большим количеством запросов на блокировку, синхронизацией и освобождением за короткий промежуток времени.
- снятие блокировки
- Устранение блокировки — это процесс JIT-компиляции виртуальной машины Java.Посредством сканирования работающего контекста удаляются блокировки, которые невозможно конкурировать за общие ресурсы.Посредством устранения блокировки можно сэкономить бессмысленное время запроса блокировки.
Что касается содержания оптимизации блокировки, статья будет подробно опубликована позже.
Сжатая передача
Перед передачей данные могут быть сжаты, чтобы уменьшить количество байтов, передаваемых по сети, и повысить скорость передачи данных.Принимающая сторона может распаковать данные для восстановления переданных данных, а сжатые данные также могут быть сохранены. пространство носителя (диск или память) и пропускную способность сети и снизить стоимость. Конечно, сжатие не обходится без накладных расходов, сжатие данных требует больших вычислительных ресурсов процессора, и, в зависимости от алгоритма сжатия, сложность вычислений и степень сжатия данных также сильно различаются. Как правило, для разных бизнес-сценариев необходимо выбирать разные алгоритмы сжатия.
кешировать результат
Для одного и того же пользовательского запроса будет потрачено много времени и ресурсов, если база данных будет неоднократно запрашиваться и повторно вычисляться. Кэшируйте результаты вычислений в локальной памяти или кэшируйте результаты через распределенный кеш, что может сэкономить драгоценные вычислительные ресурсы ЦП, уменьшить количество повторных запросов к базе данных или дисковых операций ввода-вывода и изменить физическое вращение исходной головки на одно. памяти повышает скорость отклика, а быстрое освобождение потоков также повышает пропускную способность приложения.
Ссылаться на
Подробное объяснение режима Future в многопоточном программировании на Java. Оптимизация метода блокировки Java и идеи