Рина Сергеева
Рина СергееваNov. 28, 2018, 1:58 p.m.

Several ways to synchronize processes and threads in Java

I propose to consider several ways to synchronize threads and processes that are most commonly used in Java. They differ in implementation and use cases. We will consider all methods on interesting examples.

Critical section

This method is suitable for you if:

  • parallel threads work with a shared resource;
  • requires synchronization between threads, not processes;

This method of synchronization is called resource synchronization ("open – close" synchronization). The idea of this method is that each object in Java has an associated monitor . A monitor is a kind of tool to control access to an object.


he synchronized statement is used to create a critical section. When code execution reaches the synchronized operator, the object monitor is blocked. At the time of its blocking, exclusive access to the code block has only one thread that made the blocking.After the code block finishes working, the object monitor is released and made available to other threads.

When the monitor is released, it is captured by another thread, and all other threads continue to wait for it to be released.

Example

Imagine how a retail online store works. After one of the buyers put the goods in the basket, the remaining goods should be counted. Only after that, another buyer will be able to put the desired amount of goods in the basket. After that, buy them.

public class Program {

    private static final Boolean key = true;                      //the object will be used for synchronization
                                                                  //it must be final 
    private static Integer amountOfGoods = 20;


    public static class Buyer implements Runnable {

        @Override
        public void run() {
            final int goodsInTheShoppingCart = (int) (1 + Math.random() * amountOfGoods);   //the number of goods that the buyer will put in the basket
            synchronized (key) {
                if (amountOfGoods - goodsInTheShoppingCart >= 0) {
                    System.out.println("The " + Thread.currentThread().getName() + " placed " + goodsInTheShoppingCart + " items in the basket.");
                    if ((amountOfGoods = amountOfGoods - goodsInTheShoppingCart) < 0) {
                        System.out.println("Whoops! The product is out of stock, but the " + Thread.currentThread().getName() + " didn't know about it.");
                        return;
                    } else {
                        System.out.println("There are " + amountOfGoods + " items left in the store.");
                    }
                } else {
                    System.out.println("The " + Thread.currentThread().getName() + " is notified that the goods are over.");
                    return;
                }
            }
            System.out.println("The " + Thread.currentThread().getName() + " made a purchase.");
        }
    }

    public static void main(String[] args) {

        for (int i = 1; i <= 5; i++) {
            Thread t = new Thread(new Buyer());              // create five threads
            t.setName("buyer " + i);
            System.out.println("The " + t.getName() + " went to the store website.");
            t.start();
        }
    }
}

Work of the program before using the synchronization unit

Work of the program before using the synchronization unit

We see that threads execute program code randomly. Because of this, "buyers" put the goods in baskets, but remain without goods.

Now we will add a synchronization block and see how the work of the program changes.

Work of the program using the synchronization unit

Now the program works exactly as we expected. Great!

Interface Channel

You can use Interface Channel in case you need to synchronize different processes . The channel is created at the JVM level and will be one in the system.

A channel represents an open connection to an entity such as a hardware device, a file, a network socket, or a program component that is capable of performing one or more distinct I/O operations, for example reading or writing.
A channel is either open or closed. A channel is open upon creation, and once closed it remains closed. Once a channel is closed, any attempt to invoke an I/O operation upon it will cause a ClosedChannelException to be thrown. Whether or not a channel is open may be tested by invoking its isOpen() and tryLock() methods. ).

Java package.nio.channels contains channels such as:

  • AsynchronousChannel
  • ByteChannel
  • NetworkChannel
  • FileChannel
  • InterruptibleChannel
  • MulticastChannel and other.

Example

Two processes write data to a file. They should record alternately, without interfering, in each other's work.

Let's create two projects that differ only in the fact that they will be written to a file - "Program 1" or "Program 2". We run them at the same time.

public class Program {


    public static void main(String[] args) throws InterruptedException, IOException {

        File file = new File("C:\\text.txt");
        FileChannel fileChannel = new FileOutputStream(file, true).getChannel();

        while(fileChannel.tryLock() == null){            // the process checks if the channel is free to write to the file
            Thread.sleep(10000);
        }
        try {
            String lineSeparator = System.getProperty("line.separator");

            for (int i = 0; i < 10; i++) {

                String newData = "The program 2 is recording." + lineSeparator;
                ByteBuffer buf = ByteBuffer.allocate(200);
                buf.put(newData.getBytes());
                buf.flip();
                fileChannel.write(buf);
                Thread.sleep(1000);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
        fileChannel.close();
    }
}

If we were to use the classic way of writing to a file with FileWriter, we would find something similar in the file.

Now let's see what will be in the file if we use channels.

This is exactly what we need! Processes take access to the file one by one.

Events

In addition to data synchronization, there is synchronization by events. When concurrently running threads are suspended until some event is triggered by another thread. The main operations for this type of synchronization are wait and notify.

This is a “wait – notify " synchronization”:

  • parallel threads wait for some event;
  • one of the threads is responsible for the occurrence of the event and notifies the rest of the threads(one using notify or all - notifyAll,) unlocking them:
  • only suitable for synchronization of threads, not processes;

Example

Let's imagine how the automatic weapon reloading system works. For example, only has 15 cartridges in stock. The store can only hold 6. The shooter wants to use all the cartrisges.

public class Program {

    public static void main(String[] args) {

        WeaponStore weaponStore = new WeaponStore();      
        Arsenal arsenal = new Arsenal(weaponStore);
        Shooter shooter = new Shooter(weaponStore);
        new Thread(arsenal).start();
        new Thread(shooter).start();
    }
}


class WeaponStore {                                   

    private int cartridges = 0;                       

    public synchronized void shot() {                 // synchronization of the method is required
                                                      // because two threads will have access to it
        while (cartridges < 1) {
            try {
                wait();
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
                                                      //was thrown out notify by another thread, then the cartridge is received
        cartridges--;
        System.out.println("Produced 1 shot." + " Cartridges in the store: " + cartridges);
        notify();
    }

    public synchronized void reload(int arsenalCartriges) {   // synchronization of the method is required
                                                              // because two threads will have access to it
        while (cartridges >= 6) {
            try {
                wait();
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        cartridges++;
        System.out.println("1 cartridge has been added to the store." + " Cartridges in stock: " + arsenalCartriges);
        notify();
    }
}

class Arsenal implements Runnable{                     

    private int cartridges = 15;

    private WeaponStore weapon;

    Arsenal(WeaponStore weapon){
        this.weapon = weapon;
    }

    public void run(){
        for (int cartridges = 15; cartridges > 0; cartridges--) {
            weapon.reload(cartridges);
        }
    }
}


class Shooter implements Runnable{                     

    private  WeaponStore weapon;

    Shooter(WeaponStore weapon){
        this.weapon = weapon;
    }

    public void run(){
        for (int i = 1; i <= 15; i++) {
            weapon.shot();
        }
    }
}

The result of the program

1 cartridge has been added to the store. Cartridges in stock: 15 
1 cartridge has been added to the store. Cartridges in stock: 14 
1 cartridge has been added to the store. Cartridges in stock: 13 
1 cartridge has been added to the store. Cartridges in stock: 12 
1 cartridge has been added to the store. Cartridges in stock: 11 
Produced 1 shot. Cartridges in the store: 4 
Produced 1 shot. Cartridges in the store: 3 
Produced 1 shot. Cartridges in the store: 2 
Produced 1 shot. Cartridges in the store: 1 
Produced 1 shot. Cartridges in the store: 0 
1 cartridge has been added to the store. Cartridges in stock: 10 
1 cartridge has been added to the store. Cartridges in stock: 9 
1 cartridge has been added to the store. Cartridges in stock: 8 
1 cartridge has been added to the store. Cartridges in stock: 7 
1 cartridge has been added to the store. Cartridges in stock: 6 
1 cartridge has been added to the store. Cartridges in stock: 5 
Produced 1 shot. Cartridges in the store: 5 
Produced 1 shot. Cartridges in the store: 4 
Produced 1 shot. Cartridges in the store: 3 
Produced 1 shot. Cartridges in the store: 2 
Produced 1 shot. Cartridges in the store: 1 
Produced 1 shot. Cartridges in the store: 0 
1 cartridge has been added to the store. Cartridges in stock: 4 
1 cartridge has been added to the store. Cartridges in stock: 3 
1 cartridge has been added to the store. Cartridges in stock: 2 
1 cartridge has been added to the store. Cartridges in stock: 1 
Produced 1 shot. Cartridges in the store: 3 
Produced 1 shot. Cartridges in the store: 2 
Produced 1 shot. Cartridges in the store: 1 
Produced 1 shot. Cartridges in the store: 0

Conclusion

As you noticed, the synchronization methods discussed above have different uses. Choose the right one and always synchronize your threads and processes so that they live peacefully and never interfere in each other’s work.

Subscribe to the Java section if you want more interesting articles. Write your opinion and ideas regarding this topic in the comments.

We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.

Do you like it? Share on social networks!

Comments

Only authorized users can post comments.
Please, Log in or Sign up
AD

C ++ - Test 004. Pointers, Arrays and Loops

  • Result:50points,
  • Rating points-4
m

C ++ - Test 004. Pointers, Arrays and Loops

  • Result:80points,
  • Rating points4
m

C ++ - Test 004. Pointers, Arrays and Loops

  • Result:20points,
  • Rating points-10
Last comments
Evgenii Legotckoi
Evgenii LegotckoiOct. 31, 2024, 2:37 p.m.
Django - Lesson 064. How to write a Python Markdown extension Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
A
ALO1ZEOct. 19, 2024, 8:19 a.m.
Fb3 file reader on Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
ИМ
Игорь МаксимовOct. 5, 2024, 7:51 a.m.
Django - Lesson 064. How to write a Python Markdown extension Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas5July 5, 2024, 11:02 a.m.
QML - Lesson 016. SQLite database and the working with it in QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
k
kmssrFeb. 8, 2024, 6:43 p.m.
Qt Linux - Lesson 001. Autorun Qt application under Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
Now discuss on the forum
Evgenii Legotckoi
Evgenii LegotckoiJune 24, 2024, 3:11 p.m.
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
t
tonypeachey1Nov. 15, 2024, 6:04 a.m.
google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
NSProject
NSProjectJune 4, 2022, 3:49 a.m.
Всё ещё разбираюсь с кешем. В следствии прочтения данной статьи. Я принял для себя решение сделать кеширование свойств менеджера модели LikeDislike. И так как установка evileg_core для меня не была возможна, ибо он писался…
9
9AnonimOct. 25, 2024, 9:10 a.m.
Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…

Follow us in social networks