JavaRush /Java блог /Random UA /Кава-брейк #171. Як використовувати ключове слово synchro...

Кава-брейк #171. Як використовувати ключове слово synchronized. Обробка файлів у Java

Стаття з групи Random UA

Як використовувати ключове слово synchronized

Джерело: Medium Сьогодні ви дізнаєтесь, у яких випадках і як правильно використовувати ключове слово synchronized у мові програмування Java. Кава-брейк #171.  Як використовувати ключове слово synchronized.  Обробка файлів у Java - 1Модифікатори (Modifiers) — це певні ключові слова, присутні в Java, за допомогою яких ми можемо вносити зміни до характеристик змінної, методу або класу, і обмежувати їхню дію. У мові Java є досить великий набір модифікаторів. Модифікатори Java поділяються на два типи - модифікатори доступу (Access Modifiers) і модифікатори без доступу (Non-Access modifiers).

Модифікатори без доступу

Модифікатори без доступу надають JVM інформацію про характеристики класу, методу або змінної. У Java присутні сім типів модифікаторів відсутності доступу:
  • final
  • static
  • abstract
  • synchronized
  • volatile
  • transient
  • native
У цій статті ми докладно розглянемо ключове слово synchronized . Для початку давайте визначимо, де та коли його використовувати.

У яких випадках використовується synchronized

У Java ключове слово synchronized використовується для забезпечення контролю доступу до методу або блоку коду. Коли потік намагається виконати синхронізований метод або блок коду, спочатку необхідно отримати блокування. Отримавши блокування, можна розпочати виконання. При цьому будь-який інший потік, який намагається виконати той самий синхронізований метод або блок коду, буде заблокований доти, доки перший потік не зніме блокування. Це гарантує, що тільки один потік може виконувати код одночасно, що є важливим для збереження цілісності даних. Ключове слово synchronized можна використовувати як із статичними, так і з нестатичними методами, а також із блоками коду.
  • При використанні зі статичними методами всі потоки конкурують за те саме блокування. Це може вплинути на продуктивність, тому краще уникати синхронізації статичних методів без потреби.

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

  • При використанні блоків коду блокування встановлюється на об'єкт, який передається в оператор synchronized . Це дозволяє кільком потокам одночасно виконувати синхронізовані блоки коду з різних об'єктів.

Таким чином, ключове слово synchronized є потужним інструментом для керування одночасним доступом до даних у програмах Java. При правильному використанні це може допомогти забезпечити цілісність даних та підвищити продуктивність.

Приклади використання

1. Синхронізований блок

public class Counter {
  private int count = 0;

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

  public void increment() {
    synchronized (this) {
      count++;
    }
  }
}
Тут є два блоки коду, які звертаються до лічильника. Найпростішим є метод get , який просто зчитує значення. На перший погляд, метод increment містить один рядок коду. Але пам'ятайте, що операція increment повинна зчитувати поточне значення, додавати до нього одиницю та записувати нове значення назад у пам'ять. Іншими словами, є три підоперації, які ми хочемо виконувати без переривання інших потоків. Наприклад, розміщення з іншого боку або щоб операція increment стала атомарною (atomic). Коли ми додаємо до двох блоків коду префікс ключового слова synchronized , важливо зазначити, що ми також помічаємо їх як synchronized для певного об'єкта – це показано у прикладі. Це означає, що якщо у нас є кілька об'єктів Counter , то різні потоки можуть одночасно оновлювати ці різні лічильники. Але два потоки не можуть одночасно запускати синхронізовані блоки в тому самому екземплярі Counter .

2. Метод synchronized

public class SynchronizedCounter {
    private int c = 0;

    public synchronized void increment() {
        c++;
    }

    public synchronized void decrement() {
        c--;
    }

    public synchronized int value() {
        return c;
    }
}
Якщо count є екземпляром SynchronizedCounter , то синхронізація цих методів має два ефекти:
  • По-перше, два виклики синхронізованих методів для одного і того ж об'єкта не можуть чергуватись. Коли один потік виконує метод synchronized для об'єкта, всі інші потоки, які викликають методи synchronized для того ж блоку об'єкта, припиняють виконання, поки перший потік не завершить роботу з об'єктом.

  • По-друге, коли метод synchronized завершує роботу, він автоматично встановлює значення "відбулося до" (happens-before) за будь-якого подальшого виклику методу synchronized для того ж об'єкта. Це гарантує, що зміни стану об'єкта помітні всім потокам.

Пам'ятайте, що знання того, навіщо, як і коли потрібно використовувати synchronized , а також інші модифікатори, приходить із досвідом, а досвід приходить з часом.

Обробка файлів у Java

Джерело: Usemynotes Зміст цієї публікації присвячено обробці файлів у Java. Ви ознайомитеся з операціями обробки файлів, методами класу File і різновидами потоків. Кава-брейк #171.  Як використовувати ключове слово synchronized.  Обробка файлів у Java - 2Робота з файлуми є невід'ємною частиною будь-якої програми. Використовуючи файли, програма може зберігати дані на пристрої, що запам'ятовує. Для виконання різних дій із файлом, таких як читання або запис, потрібна обробка файлу. Обробка файлів визначається як читання з файлу та запис у файл. Для створення файлового об'єкта та обробки різних форматів файлів ми можемо використовувати клас File із пакета java.io. Якщо ми хочемо використовувати клас File, нам потрібно створити об'єкт класу File та вказати ім'я файлу або шлях. Використовуючи цей клас, ми можемо отримати доступ до метаданих файлів, таких як ім'я файлу, розмір файлу, роздільна здатність, тип файлу і так далі.
// importing all the classes of java.io
import java.io.*;
class FileHandle {
    public static void main(String[] arr) {
       // an object of File class is created.
       File f=new File("demo.txt");
}
}
Для імпорту класу File також можна використовувати import java.io.File замість import java.io.* . Тепер давайте дізнаємося про потоки, оскільки Java використовує потоки для виконання операцій вводу-виводу (I/O) над файлом.

Що таке потік у Java?

Потік (Stream) – це послідовність даних. Також його можна визначити як послідовність байтів. Потік можна використовувати для подання джерела введення або пункту призначення. Джерелом та місцем призначення можуть бути файли на диску, масиви, текстові файли тощо. Вхідний потік зчитує або витягує дані з джерела, а вихідний потік записує дані до місця призначення. Існує два типи потоків:

Байтовий потік

Байтовий потік (Byte Stream) використовується для виконання операцій читання та запису з байтовими даними. Процес обробки файлу потоку байтів визначається як виконання введення з використанням байтових даних. Існує безліч класів, пов'язаних з потоками байтів, але найчастіше використовувані класи - це FileInputStream і FileOutputStream .
import java.io.*;
public class FileHandle{
   public static void main(String []arr) throws IOException{
   FileInputStream fin=new FileInputStream("source_file.txt");
   FileOutputStream fout=new FileOutputStream("destination_file.txt");
   int character;
   while((character=fin.read())!=-1)
   {
      System.out.print((char)character);
      // writing to destination file
      fout.write((char)character);
   }
   // closing source_file.txt
   fin.close();
   // closing destination_file.txt
   fout.close();
 }
}
У наведеному вище прикладі читаємо дані з вихідного файлу і записуємо дані в місце призначення. -1 вказує на кінець файлу. Таким чином читання з вихідного файлу буде зупинено, коли з'явиться -1.

Потік символів

Потік символів (Character Stream) використовується для виконання операцій читання та записування з символьними даними. Процес обробки файлу із потоком символів – це процес виконання вхідних даних із символами. Доступно безліч класів символьних потоків, але найчастіше використовувані класи включають FileWriter і FileReader . А зараз давайте обговоримо деякі методи класу File .

Методи класу File у Java

canRead()

Цей метод класу файлів перевіряє, чи доступний файл для читання, і повертає логічне значення, тобто справжнє ( true ) або хибне ( false ).

canWrite()

Це метод класу файлів, який перевіряє, чи доступний файл для запису, і повертає логічне значення, тобто справжнє чи хибне.

exists()

Це метод файлового класу, який використовується для перевірки наявності файлу і повертає логічне значення.

createNewFile()

Коли ми хочемо створити новий пустий файл, використовуйте цей метод класу файлів. Він повертає логічне значення.

delete()

Це метод класу файлу, який використовується для видалення файлу та повернення логічного значення.

getAbsolutePath()

Цей метод використовується для повернення абсолютного шляху файлу. getName()Це метод, який використовується для повернення строкового значення, яке є ім'ям файлу.

list()

Він повертає масив рядків, які представляють усі файли в каталозі.

length()

Цей спосіб класу файлу повертає розмір файлу в байтах.

mkdir()

Це метод файлового класу, який використовується для створення нового каталогу. Погляньмо на різні файлові операції, доступні в Java, і на те, як їх використовувати.

Що таке файлові операції у Java?

При обробці файлів Java ми можемо виконувати такі операції з файлом:
  • Створення файлу
  • Запис даних у файл
  • Читання даних із файлу
  • Видалення файлу
  • Отримання інформації про файл
  • Створення файлу
У Java можна створити файл, використовуючи метод createNewFile() класу File . Цей метод повертає true , якщо файл створено, інакше повертається false , якщо вже існує файл.
import java.io.*;
public class FileHandle{
   public static void main(String []arr) throws IOException{
   // an object of file class
   File f=new File("demo.txt");
   // creating a new file
   Boolean result=f.createNewFile();
   if(result)
      System.out.print(f+" created successfully.");
   else
      System.out.format("%s","File cannot be created due to some error.");
 }
}

Запис даних у файл

Операція запису у файл означає збереження даних у файлі. Для виконання операцій запису файл ми використовуємо метод write() разом із класом FileWriter . Щоб закрити потік та отримати виділені ресурси, ми маємо використовувати метод close() .
import java.io.*;
public class FileHandle{
   public static void main(String []arr) throws IOException{
     // creating a new file and writing data to a file
     FileWriter fw=new FileWriter("demo.txt");
     String s="Welcome, this is tutorial of Java File Handling.";
     fw.write(s);
     // closing a file
     fw.close();
   }
}

Читання з файлу

Операція читання означає доступ або вилучення даних, що зберігаються у файлі. Щоб виконати операцію запису у файл, ми будемо використовувати клас Scanner разом з методами hasNextLine() та nextLine() для вилучення даних із файлу. Щоб закрити потік, необхідно використовувати метод close() .
import java.io.*;
import java.util.Scanner;
public class FileHandle{
   public static void main(String []arr) throws IOException{
     File f=new File("demo.txt");
     Scanner sc=new Scanner(f);
     while(sc.hasNextLine())
     {
       String str=sc.nextLine();
       System.out.println(str);
     }
     // closing a file
     sc.close();
   }
}

Видалення файлу

Під час обробки файлів Java ми можемо видалити файл, використовуючи метод delete() класу File . Тут немає необхідності закривати файл за допомогою функції close() , оскільки для видалення файлу не використовуються класи FileWriter та Scanner .
import java.io.*;
public class FileHandle{
   public static void main(String []arr) throws IOException{
      File f=new File("demo.txt");
      Boolean result=f.delete();
      if(result)
         System.out.print(f+" deleted successfully.");
      else
         System.out.format("%s","File cannot be deleted due to some error.");
   }
}

Отримання інформації про файл

Java має кілька методів для отримання інформації про файл. Вони вже згадувалися раніше у методах класу файлу.
import java.io.*;
public class FileHandle{
   public static void main(String []arr) throws IOException{
     File file=new File("demo.txt");
     file.createNewFile();
     String filename=file.getName();
     System.out.println("File Name is "+filename);
     System.out.println("Absolute path of "+filename+" : "+file.getAbsolutePath());
     System.out.print("length of "+filename+" : "+file.length());
     System.out.println("Is "+filename+" readable? "+file.canRead());
     System.out.println("Is "+filename+" writable? "+file.canWrite());
     System.out.println("Is "+filename+" exists? "+file.exists());
  }
}
Давайте розглянемо роботу однієї Java-програми, яка визначає, чи є число парним чи непарним, використовуючи потік масиву байтів під час обробки файлів Java. Для написання цієї програми ми будемо використовувати клас ByteArrayInputStream з пакету java.io. Цей клас містить буфер, який використовується для читання масиву байтів як вхідний поток. Нижче наведено код для перевірки парних чи непарних чисел.
import java.io.*;
public class FileHandle{
   public static void main(String []arr) throws IOException{
     byte []buffer={10,40,81,23,32,100,57};
     ByteArrayInputStream by=new ByteArrayInputStream(buffer);

     int character=0;
     while((character=by.read())!=-1)
     {
        int number=character;
        if(number%2==0)
          System.out.println(number+" is an even number.");
        else
          System.out.println(number+" is an odd number.");
     }
   }
}
Сподіваюся, представлена ​​тут інформація була корисною для вас. Щоб краще зрозуміти роботу з файлуми в Java, ви повинні спробувати реалізувати всі методи файлів і операцій самостійно.
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ