Java for Beginner
676 subscribers
546 photos
155 videos
12 files
836 links
Канал от новичков для новичков!
Изучайте Java вместе с нами!
Здесь мы обмениваемся опытом и постоянно изучаем что-то новое!

Наш YouTube канал - https://www.youtube.com/@Java_Beginner-Dev

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
Метод Thread.sleep()

В Java метод Thread.sleep() — это статический метод класса Thread, который позволяет временно приостановить выполнение текущего потока. Это очень полезная функция, особенно когда вам нужно дать другим потокам возможность работать, а также для создания задержек в выполнении программ.

Основы работы с Thread.sleep()

Сигнатура метода выглядит так:
public static native void sleep(long millis) throws InterruptedException;
public static void sleep(long millis, int nanos) throws InterruptedException;
millis — время в миллисекундах, на которое поток должен быть приостановлен.
nanos — дополнительное время в наносекундах (второй вариант метода).


Внутреннее устройство

Когда вы вызываете Thread.sleep(), текущий поток переходит в состояние "ожидания". Это состояние отличается от состояния "блокировки", так как поток не может быть разбужен, пока не истечет указанный период времени или пока его не прервет другой поток (например, с помощью метода interrupt()).

Внутренне Thread.sleep() использует механизм планирования потоков операционной системы. Это значит, что управление возвращается в операционную систему, которая решает, какой поток должен быть выполнен в данный момент времени.


Применение

Метод Thread.sleep() часто используется в следующих ситуациях:
Создание временной задержки. Например, если вы хотите, чтобы программа ждала несколько секунд перед выполнением следующей операции.
Синхронизация потоков. Если у вас несколько потоков, и вам нужно, чтобы один из них подождал завершения другого.
Тестирование. Во время тестирования асинхронного кода, вы можете использовать sleep() для имитации задержек.


Примеры использования

Пример 1: Простая задержка
public class SleepExample {
public static void main(String[] args) {
System.out.println("Программа начинается.");
try {
Thread.sleep(2000); // Ожидание 2 секунды
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("2 секунды прошли.");
}
}


Пример 2: Синхронизация потоков
public class SleepSynchronization {
public static void main(String[] args) {
Thread thread1 = new Thread(new Task("Поток 1"));
Thread thread2 = new Thread(new Task("Поток 2"));

thread1.start();
thread2.start();
}
}

class Task implements Runnable {
private String name;

public Task(String name) {
this.name = name;
}

public void run() {
try {
System.out.println(name + " запущен.");
Thread.sleep(1000); // Ожидание 1 секунда
System.out.println(name + " завершен.");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}


Важно помнить

Использование Thread.sleep() может приводить к неэффективному использованию ресурсов, так как поток, который "спит", не выполняет никакой работы.
Если поток прерывается во время сна, выбрасывается исключение InterruptedException, и вам нужно корректно его обрабатывать.


#Java #Training #Medium #Thread_sleep
Что выведет код?

public class Task101024_1 {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
try {
System.out.print("A");
Thread.sleep(500);
System.out.print("B");
} catch (InterruptedException e) {
System.out.print("E");
}
});

Thread t2 = new Thread(() -> {
try {
System.out.print("C");
Thread.sleep(200);
System.out.print("D");
} catch (InterruptedException e) {
System.out.print("F");
}
});

t1.start();
t2.start();
t1.join();
t2.join();
}
}


#Tasks
Варианты ответа:
Anonymous Quiz
42%
ACBD
8%
CABD
33%
ACDB
17%
CDAB
0%
ACAB
А еще это переработчик кофе. Из одного внутреннего состава в другое. 😂👍

Подписывайтесь на канал, у нас интересно - https://t.me/Java_for_beginner_dev

#Mems
Что выведет код?

import java.util.regex.*;

public class Task101024_2 {
public static void main(String[] args) {
String input = "a1b2c3";
Pattern pattern = Pattern.compile("\\d");
Matcher matcher = pattern.matcher(input);

StringBuilder result = new StringBuilder();
while (matcher.find()) {
result.append(matcher.group());
}
System.out.println(result.toString());
}
}


#Tasks
Варианты ответа:
Anonymous Quiz
18%
abc
27%
a1b2c3
0%
c3
55%
123
0%
java
Класс TimeUnit

Класс TimeUnit из пакета java.util.concurrent предоставляет удобный способ работы с временными единицами. Он позволяет выполнять преобразования между различными единицами времени и упрощает работу с многопоточностью, особенно при использовании методов, которые требуют указания времени ожидания.

Основы класса TimeUnit

Класс TimeUnit реализует перечисление (enum), содержащее семь основных временных единиц:

NANOSECONDS - наносекунды
MICROSECONDS - микросекунды
MILLISECONDS - миллисекунды
SECONDS - секунды
MINUTES - минуты
HOURS - часы
DAYS - дни

Каждая единица времени в TimeUnit поддерживает методы для преобразования в другие единицы и для ожидания.

Внутреннее устройство

Класс TimeUnit не имеет внутреннего состояния, так как это перечисление. Все методы статические, и они принимают входные значения, которые вы передаете в виде аргументов. Это делает класс очень удобным и легким в использовании.

Применение

Класс TimeUnit используется в различных ситуациях:
Упрощение кода. Он позволяет избежать неочевидных преобразований между различными единицами времени, делая код более читаемым и понятным.
Управление потоками. Использование методов sleep() и awaitTermination() из ExecutorService с классом TimeUnit помогает избежать ошибок, связанных с неправильными единицами времени.
Тестирование. Класс удобно использовать для создания временных задержек в тестах.


Примеры использования

Пример 1: Преобразование единиц времени
import java.util.concurrent.TimeUnit;

public class TimeUnitExample {
public static void main(String[] args) {
long hours = 2;
long minutes = TimeUnit.HOURS.toMinutes(hours);
long seconds = TimeUnit.HOURS.toSeconds(hours);

System.out.println(hours + " часа = " + minutes + " минут.");
System.out.println(hours + " часа = " + seconds + " секунд.");
}
}


Пример 2: Ожидание с использованием TimeUnit
import java.util.concurrent.TimeUnit;

public class TimeUnitSleepExample {
public static void main(String[] args) {
System.out.println("Программа начинается.");
try {
TimeUnit.SECONDS.sleep(2); // Ожидание 2 секунды
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("2 секунды прошли.");
}
}


Пример 3: Использование с ExecutorService
import java.util.concurrent.*;

public class ExecutorServiceExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(1);

executor.submit(() -> {
try {
System.out.println("Задача началась.");
TimeUnit.SECONDS.sleep(3); // Ожидание 3 секунды
System.out.println("Задача завершена.");
} catch (InterruptedException e) {
e.printStackTrace();
}
});

executor.shutdown();
try {
if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
executor.shutdownNow(); // Принудительное завершение
}
} catch (InterruptedException e) {
executor.shutdownNow();
}
}
}


Важно помнить

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


#Java #Training #Medium #TimeUnit
Память в JVM

Основные компоненты памяти в JVM

Когда программа на Java выполняется, JVM распределяет память между различными внутренними структурами и объектами. Память в JVM делится на несколько областей, каждая из которых выполняет определенную роль. Основные области памяти включают:


Heap (Куча):

Используется для динамического размещения объектов во время выполнения программы.
Все объекты и их данные (например, строки, массивы и т.д.) хранятся здесь.
Разделена на несколько генераций: Young Generation, Old (Tenured) Generation и Permanent Generation (PermGen) (до Java 8) или Metaspace (с Java 8).
Управляется сборщиком мусора (Garbage Collector, GC), который отвечает за освобождение памяти от неиспользуемых объектов.


Stack (Стек):

Хранит вызовы методов и локальные переменные каждого потока.
Каждый поток имеет свой собственный стек.
В каждой области стека находятся кадры (stack frames), которые содержат локальные переменные, параметры метода и указатели на объекты в куче.
Стек управляется автоматически: память освобождается при завершении выполнения метода.


Method Area (Методная область):

Используется для хранения метаданных классов, таких как данные о методах, переменных и константах.
До Java 8 эта область была частью PermGen, с Java 8 ее заменила Metaspace.
Размер Metaspace не ограничен памятью JVM, а зависит от объема доступной оперативной памяти системы.


Program Counter Register (Регистры счетчика программы):

Хранит адрес текущей выполняемой инструкции для каждого потока.
При переключении контекста потоков каждый поток сохраняет свое состояние с помощью этого регистра.


Native Method Stack (Стек нативных методов):

Используется для хранения данных, связанных с вызовом нативных методов (методы, написанные на других языках, таких как C или C++).
Содержит информацию, необходимую для взаимодействия с библиотеками и операционной системой.


Устройство и работа Heap

Куча (Heap) является самой большой и сложной областью памяти JVM. Она делится на несколько частей:

Young Generation (Молодое поколение):

Новые объекты создаются сначала в этой области.
Молодое поколение делится на три области: Eden, Survivor Space 1 и Survivor Space 2.
Когда область Eden заполняется, выполняется минорная сборка мусора (Minor GC), после которой живые объекты перемещаются в Survivor Space.


Old Generation (Старшее поколение):

Объекты, которые пережили несколько циклов сборки мусора в Young Generation, перемещаются в Old Generation.
В этой области хранятся долгоживущие объекты, такие как статические данные или объекты, которые остаются актуальными на протяжении всего выполнения программы.
Сборка мусора в этой области называется Major GC или Full GC.


#Java #Training #Medium #JVM
Metaspace

Метаданные классов хранятся здесь.
Metaspace автоматически расширяется при необходимости, если в системе достаточно свободной памяти.
Взаимодействие компонентов памяти


При выполнении программы Java каждая из этих областей играет определенную роль:

Когда метод вызывается, создается новый кадр стека, и локальные переменные, параметры метода и ссылки на объекты помещаются в этот кадр.
Если метод создает новый объект, он размещается в области Eden в куче.
Взаимодействие между стеками и кучей осуществляется посредством указателей. Например, объект, созданный в куче, может быть доступен по ссылке, которая хранится в стеке.
Когда метод завершает выполнение, кадр стека удаляется, и локальные переменные больше не существуют, но если объект был создан в куче и на него еще существуют ссылки, объект продолжает существовать.

Пример кода и распределение памяти
public class MemoryExample {
public static void main(String[] args) {
int localVariable = 10; // Локальная переменная в стеке
String greeting = "Hello, World!"; // Строка в пуле строк (String Pool)
Object obj = new Object(); // Объект в куче
MemoryExample example = new MemoryExample(); // Новый экземпляр в куче
example.printGreeting(greeting);
}

public void printGreeting(String message) {
System.out.println(message); // Параметр метода в стеке
}
}


Локальная переменная localVariable создается в стеке.
Строка greeting хранится в пуле строк (особая часть кучи, где хранятся строковые литералы).
Объект obj создается в области Eden в куче.
Экземпляр MemoryExample также создается в куче.
При вызове метода printGreeting создается новый кадр стека, в который передается параметр message.


Особенности управления памятью

Сборка мусора (Garbage Collection):
Сборщик мусора автоматически освобождает память от объектов, на которые нет ссылок.
В JVM используется несколько алгоритмов сборки мусора: Serial GC, Parallel GC, CMS (Concurrent Mark-Sweep) и G1 (Garbage First).
Выбор сборщика мусора зависит от требований приложения и его характеристик (например, интерактивные приложения могут предпочитать CMS, а серверные — G1).


Проблемы утечек памяти (Memory Leaks):

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


Оптимизация использования памяти:

Использование пулов объектов и избегание создания избыточных экземпляров.
Правильное управление объемом кучи с помощью параметров JVM (-Xmx и -Xms).


#Java #Training #Medium #JVM
Что выведет код?

public class Task111024 {
private static int counter = 0;

static {
counter += 5;
System.out.println("Static block: " + counter);
}

{
counter += 10;
System.out.println("Instance block: " + counter);
}

public Main() {
counter += 20;
System.out.println("Constructor: " + counter);
}

public static void main(String[] args) {
System.out.println("Main Start: " + counter);
Main obj = new Main();
System.out.println("Main End: " + counter);
}
}


#Tasks
О, наконец-то нормальный девиз😂

https://t.me/Java_for_beginner_dev

#Mems
Java Memory Model (JMM)

Java Memory Model (JMM) определяет, как изменения в памяти, производимые одним потоком, становятся видимыми другим потокам. JMM описывает:
Как потоки взаимодействуют с основной памятью.
Правила синхронизации доступа к переменным.
Гарантии порядка операций, чтобы избежать непредсказуемого поведения в многопоточном программировании.
Главной целью JMM является устранение несогласованности данных и определение поведения программы на уровне видимости и порядка выполнения операций в многопоточной среде.


Основные концепции JMM

Главная (основная) память (Main Memory):
Это область памяти, где хранятся все общие переменные (поля классов, статические переменные и т. д.).
Каждому потоку также выделяется собственная локальная память (Thread Local Memory), где временно сохраняются копии значений переменных.


Кэширование и локальная память потоков:
Потоки могут не сразу обращаться к основной памяти. Вместо этого они используют кэш или локальную копию переменных.
Изменения, сделанные в локальной памяти одного потока, могут не быть видны другим потокам, если они не будут синхронизированы с основной памятью.


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


Инструкции и пересортировка:
Компилятор и процессор могут менять порядок выполнения операций для оптимизации.
Например, две независимые операции могут поменяться местами, если это ускорит выполнение программы. JMM устанавливает правила, чтобы такая пересортировка не нарушала корректность многопоточной программы.


#Java #Training #Medium #JMM
Правила JMM для взаимодействия потоков

JMM включает несколько базовых правил для обеспечения корректного поведения программы:

Правило Happens-Before:
Если одна операция происходит "раньше" другой с точки зрения JMM, это означает, что все изменения, сделанные первой операцией, будут видны второй.
Например, вызов Thread.start() имеет отношение happens-before к всем действиям внутри нового потока.


Правило синхронизации (synchronized блоки):
Использование ключевого слова synchronized гарантирует, что все изменения, сделанные внутри блока, будут видны другим потокам после выхода из него.
class Counter {
private int count = 0;

public synchronized void increment() {
count++; // Этот блок синхронизирован, изменения видны другим потокам.
}

public synchronized int getCount() {
return count;
}
}


Volatile-переменные:

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

class FlagExample {
private volatile boolean flag = false;

public void setFlagTrue() {
flag = true;
}

public void checkFlag() {
if (flag) {
System.out.println("Flag is true!");
}
}
}


Конструкторы и финализация:
Все операции, выполненные в конструкторе, должны быть завершены до того, как ссылка на объект станет доступной другим потокам.
Это правило предотвращает "полуинициализированные" объекты в многопоточной среде.
Внутреннее устройство JMM и управление памятью


На уровне устройства, JMM опирается на низкоуровневую архитектуру процессора и системы памяти:

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


Барьеры памяти (Memory Barriers):
JMM вводит так называемые барьеры памяти (memory barriers или fences) для обеспечения правильного порядка операций.
Существуют два типа барьеров:
Барьеры записи (Write Barrier) — гарантируют, что все предшествующие записи переменных видны другим потокам.
Барьеры чтения (Read Barrier) — гарантируют, что все последующие операции чтения переменных происходят после предыдущих операций записи.


Пересортировка (Reordering):
Компилятор и процессор могут изменять порядок инструкций для повышения производительности.
int x = 0, y = 0;
x = 1; // A
y = x + 1; // B
// Компилятор может поменять A и B местами, если это ускоряет выполнение.


Final-поля:
Поля, объявленные как final, имеют особые гарантии: они инициализируются до того, как объект станет доступен другим потокам.
Это предотвращает утечки ссылок на не полностью инициализированные объекты.


Пример нарушения JMM
Рассмотрим типичную проблему гонки данных:
class SharedObject {
private int counter = 0;

public void increment() {
counter++; // Несинхронизированный доступ к переменной.
}

public int getCounter() {
return counter;
}
}
Если несколько потоков одновременно вызывают метод increment, результат может быть непредсказуемым из-за отсутствия синхронизации: один поток может перезаписать значение, измененное другим потоком.


Правильное использование JMM

Для обеспечения корректности программы в многопоточной среде можно использовать следующие механизмы:

Использование synchronized для метода increment():
public synchronized void increment() {
counter++;
}
Применение AtomicInteger для безопасного инкремента:

java
Копировать код
import java.util.concurrent.atomic.AtomicInteger;

class SharedObject {
private AtomicInteger counter = new AtomicInteger(0);

public void increment() {
counter.incrementAndGet(); // Безопасная атомарная операция.
}

public int getCounter() {
return counter.get();
}
}


#Java #Training #Medium #JMM
Всем доброго субботнего утра!☀️

Ничего больше писать не буду, все равно никто не отвечает😂

Просто хороших выходных каждому и даром!🍻🖐
Хоть какая то польза от работы программистом😂😂😂

https://t.me/Java_for_beginner_dev

#Mems
This media is not supported in your browser
VIEW IN TELEGRAM
Всем доброго утра!🖐

Сегодня в 16:00 по МСК, мы вновь соберемся, что покодить)))
Сегодня мы напишем чат, и попробуем запустить его для работы через удаленный сервер!
😱

Жду всех, будет интересно!)
Ссылка на встречу опубликована в нашем чате - https://t.me/Java_Beginner_chat

Присоединяйтесь!
Создаем свой чат! Размещаем его на удаленном сервере.

Запись нашей сегодняшней встречи -
YOUTUBE
RUTUBE

Спасибо огромное тем кто пришел, я правда старался для Вас) Надеюсь все понравилось! 🙏

На сегодняшней встрече с подписчиками, мы создали клиент - серверный чат, и разместили сервер чата на удаленном виртуальном сервере! Рассмотрели на примере работу с библиотекой Swing, классом Socket и многопоточкой)))

Код на GitHUB - https://github.com/Oleborn/ChatProject.git

Смотрите, комментируйте, задавайте вопросы! Обязательно подписывайтесь на ютуб и рутюб каналы!!!

Всем хорошего вечера и отличного общения! 🫡✌️
Сборка мусора в Java

Сборка мусора (Garbage Collection, GC) — это автоматический процесс управления памятью, который освобождает объекты, больше не используемые программой. Главная задача GC — найти объекты, которые недостижимы, и освободить занимаемую ими память для повторного использования. Программистам в Java не нужно вручную управлять выделением и освобождением памяти (как, например, в языках C/C++), что значительно упрощает разработку и снижает количество ошибок, связанных с утечками памяти.

Память в Java разделена на две основные части: кучу (Heap) и стек (Stack). Объекты, создаваемые динамически (например, при вызове new), размещаются в куче и занимают определенное место до тех пор, пока они не станут недостижимыми. Если ненужные объекты не будут удаляться, память заполнится, что приведет к сбою программы из-за OutOfMemoryError.

Garbage Collector автоматически отслеживает и удаляет такие объекты, поддерживая память в чистоте и предотвращая утечки.

Основные концепции сборки мусора

Перед тем как погрузиться в детали, рассмотрим несколько ключевых понятий, связанных с управлением памятью в Java:

Достижимость объектов:
Объект считается достижимым, если на него есть ссылки из активных частей программы (например, глобальные переменные или переменные метода).
Недостижимый объект — это объект, на который нет ссылок, и он не может быть использован в дальнейшем.


Корни GC (GC Roots):
GC Roots — это специальные точки входа, от которых начинается проверка достижимости объектов.
Примеры GC Roots: активные потоки, статические поля классов, локальные переменные методов, ссылки из JNI (Java Native Interface).


Алгоритмы сборки мусора:
Существуют различные алгоритмы для отслеживания достижимости объектов: маркировка и удаление (Mark and Sweep), копирование (Copying), сжатие (Compaction) и другие.
Алгоритмы также могут отличаться по стратегии: минорная (Minor GC) и полная сборка (Full GC).


Молодое и старое поколения (Young и Old Generation):

Java-куча делится на несколько регионов:
Young Generation — область, в которой создаются новые объекты. В эту область чаще всего попадает сборка мусора.
Old Generation — сюда перемещаются более «долгоживущие» объекты. Сборка в этом регионе происходит реже, но является более затратной.


Как работает сборка мусора в JVM?

Java использует комбинацию разных алгоритмов и стратегий для эффективного управления памятью:

Mark and Sweep:
Основной алгоритм, используемый в большинстве JVM.
Маркировка (Mark): GC проходит по всем доступным объектам и помечает их как "достижимые".
Удаление (Sweep): Все объекты, которые не были помечены, удаляются.


Copying:
Этот алгоритм используется в Eden-области (молодое поколение).
Вся Young Generation делится на Eden и два Survivor пространства (From и To).
Когда Eden заполняется, GC перемещает все активные объекты в Survivor To область и очищает Eden.


Generational Garbage Collection:
JVM разделяет память на разные поколения:
Young Generation — для новых объектов.
Old Generation — для объектов, которые пережили несколько сборок.
Объекты перемещаются из Young в Old по мере увеличения их "возраста".


Compact and Defragmentation:
После удаления недостижимых объектов память может стать фрагментированной.
Для предотвращения фрагментации, GC может выполнять сжатие (compaction), перемещая объекты в соседние участки памяти.


#Java #Training #Medium #Garbage_collector
Типы сборок мусора в Java

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


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


Parallel GC (или Throughput Collector):
Использует несколько потоков для сборки мусора.
Хорош для многопоточных приложений, стремящихся минимизировать время пауз.


CMS (Concurrent Mark-Sweep):
Предназначен для минимизации пауз при сборке мусора.
Выполняет маркировку и удаление объектов одновременно с выполнением программы.

Более ресурсоемкий и требует больше CPU.

G1 (Garbage First):

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


ZGC и Shenandoah:
Современные сборщики мусора с низкими паузами.
Ориентированы на большие кучи и высокую производительность.
Особенности сборки мусора в разных регионах памяти


Память в JVM делится на несколько регионов, каждый из которых имеет свои особенности:

Young Generation:
Основные области: Eden, Survivor From, Survivor To.
В этой области происходят минорные сборки (Minor GC) — сборки, которые удаляют недостижимые объекты в молодом поколении.


Old Generation:
Сюда попадают объекты, которые "пережили" несколько минорных сборок.
Сборка в этой области называется Full GC или Major GC и является более затратной по времени.


Permanent Generation (Metaspace):
Содержит метаинформацию, загружаемые классы и методы.
В более новых версиях JVM (с Java 8) эта область была заменена на Metaspace, которая динамически расширяется по мере необходимости.


#Java #Training #Medium #Garbage_collector