Privacy policyContactsAbout siteOpinionsGitHubDonate
© EVILEG 2015-2018
Recommend hosting
TIMEWEB

Several ways to synchronize processes and threads in Java

processes, Java, synchronization, threads

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.



The 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






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.










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.

Comment

Comment

Only authorized users can write comments.
Sign in or Register, Please
Dec. 12, 2018, 6:49 p.m.
Yaroslav Chernetskyi

Qt - Test 001. Signals and slots

  • Result:31points,
  • Rating scores-10
Dec. 12, 2018, 6:19 a.m.
nikbobrecov

Qt - Test 001. Signals and slots

  • Result:57points,
  • Rating scores-2
Dec. 11, 2018, 6:59 p.m.
Feniks3000

C++ - Тест 003. Условия и циклы

  • Result:71points,
  • Rating scores1
Recent comments
Dec. 11, 2018, 9:01 p.m.
Евгений Легоцкой

Не знаю, какой-там конкретно эффект и если честно не хочется fl studio ради того, чтобы посмотреть устанавливать, но из того, что увидел в интернете. Предполагаю, что то, что вы хотите с...
Dec. 11, 2018, 7:25 p.m.
Vlad15007

Подскажите пожалуйста ( я новичок совсем)Можно ли организовать спрайт без этого окошка (как в fl studio fruity dance)?
Dec. 11, 2018, 3:06 p.m.
Евгений Легоцкой

Что интересно, если написать так from <application_name>.<module_name> import <filename> ,то PyCharm сносит крышу, если разрабатываешь в рамках проекта приложение, ко...
Dec. 11, 2018, 2:52 p.m.
Илья Чичак

Тут мне тоже есть что сказать=) Сами разрабы советуют импортировать следующим образом: from <application_name> import <module_name> Стоит избегать from . import &l...;
Dec. 11, 2018, 2:28 p.m.
Евгений Легоцкой

Твоя правда. Согласен. Свои миграции храню в репозитории. На продакшене только выполняю обновление структуры базы данных, после тестирования на дев сервере конечно (читай локальная машина разр...
Now discuss on the forum
Dec. 12, 2018, 5:52 p.m.
Михаиллл

Оказывается оно все переводит в нижний регистр и нужно так писать: SearchTableModel->setTable("\"Test2\"");
Dec. 12, 2018, 4:32 p.m.
Булат Гиниятов

Допустим в MyObject *myobject = new MyObject; есть метод start(){while(aaa){////////////////}} Как мне обратиться к методу stop(){aaa=false;} ? Соответственно по...
Dec. 12, 2018, 4:28 p.m.
xintrea

Как выяснилось в этом обсуждении: Отправка Email из Android в Qt для отправки Email в Android необходимо делать Java-метод, который и будет отправлять email. И этот Java-мет...
Dec. 12, 2018, 3:35 p.m.
lynx

если кому будет вдруг нужно, подумал я над предложением Евгения Но думаю, что проще какой-то функционал дополнить для TableView из Qt Quick Controls 2. вообще берем стандарт...
Dec. 12, 2018, 1:49 p.m.
Евгений Легоцкой

но у меня нет времени учиться ВЕЧНО давайте без истерик, вы это говорите человеку, который всю жизнь учился, учится и будет учиться, и в программировании всегда так, или учишься и...
Join us in social networks

For registered users on the site there is a minimum amount of advertising