JavaRush /Java Blog /Random EN /Level 26. Answers to interview questions on the level top...
zor07
Level 31
Санкт-Петербург

Level 26. Answers to interview questions on the level topic. Part 2. Questions 6-9, 11-12

Published in the Random EN group
Level 26. Answers to interview questions on the level topic.  Part 2. Questions 6-9, 11-12 - 1

6. What is Cancarenzi?

Concurrency is a class library in Java that contains special classes optimized for working across multiple threads. These classes are collected in a package java.util.concurrent. They can be schematically divided according to functionality as follows: Level 26. Answers to interview questions on the level topic.  Part 2. Questions 6-9, 11-12 - 2Concurrent Collections - a set of collections that work more efficiently in a multi-threaded environment than standard universal collections from java.utilthe package. Instead of a basic wrapper Collections.synchronizedListwith blocking access to the entire collection, locks on data segments are used, or work is optimized for parallel reading of data using wait-free algorithms. Queues - non-blocking and blocking queues with multi-threading support. Non-blocking queues are designed for speed and operation without blocking threads. Blocking queues are used when you need to “slow down” the “Producer” or “Consumer” threads if some conditions are not met, for example, the queue is empty or overflowed, or there is no free “Consumer”. Synchronizers are auxiliary utilities for synchronizing threads. They are a powerful weapon in “parallel” computing. Executors - contains excellent frameworks for creating thread pools, scheduling asynchronous tasks and obtaining results. Locks - represents alternative and more flexible thread synchronization mechanisms compared to the basic synchronizedones . Atomics - classes with support for atomic operations on primitives and references. Source:waitnotifynotifyAll

7. What classes from Kankarensi do you know?

The answer to this question is perfectly stated in this article . I don’t see the point in reprinting it all here, so I will give descriptions only of those classes that I had the honor of briefly familiarizing myself with. ConcurrentHashMap<K, V> - Unlike Hashtableand blocks synhronizedon HashMap, the data is presented in the form of segments, divided into hashes of keys. As a result, data is accessed by segments rather than by single object. In addition, iterators represent data for a specific period of time and do not throw ConcurrentModificationException. AtomicBoolean, AtomicInteger, AtomicLong, AtomicIntegerArray, AtomicLongArray - What if in a class you need to synchronize access to one simple variable of type int? You can use constructs with synchronized, and when using atomic operations set/get, volatile. But you can do even better by using new classes Atomic*. Due to the use of CAS, operations with these classes are faster than if synchronized via synchronized/volatile. Plus, there are methods for atomic addition by a given amount, as well as increment/decrement.

8. How does the ConcurrentHashMap class work?

By the time of its introduction, ConcurrentHashMapJava developers needed the following hash map implementation:
  • Thread safety
  • No locks on the entire table while accessing it
  • It is desirable that there are no table locks when performing a read operation
The main implementation ideas ConcurrentHashMapare as follows:
  1. Map elements

    Unlike elements HashMap, Entryin ConcurrentHashMapare declared as volatile. This is an important feature, also due to changes in JMM .

    
    static final class HashEntry<K, V> {
        final K key;
        final int hash;
        volatile V value;
        final HashEntry<K, V> next;
    
        HashEntry(K key, int hash, HashEntry<K, V> next, V value) {
            this .key = key;
            this .hash = hash;
            this .next = next;
            this .value = value;
         }
    
        @SuppressWarnings("unchecked")
        static final <K, V> HashEntry<K, V>[] newArray(int i) {
            return new HashEntry[i];
        }
    }
  2. Hash function

    ConcurrentHashMapan improved hashing function is also used.

    Let me remind you what it was like in HashMapJDK 1.2:

    
    static int hash(int h) {
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }

    Version from ConcurrentHashMap JDK 1.5:

    
    private static int hash(int h) {
        h += (h << 15) ^ 0xffffcd7d;
        h ^= (h >>> 10);
        h += (h << 3);
        h ^= (h >>> 6);
        h += (h << 2) + (h << 14);
        return h ^ (h >>> 16);
    }

    Why is there a need to make the hash function more complex? The tables in a hash map have a length determined by a power of two. For hash codes whose binary representations do not differ in low and high position, we will have collisions. Increasing the complexity of the hash function just solves this problem, reducing the likelihood of collisions in the map.

  3. Segments

    The map is divided into N different segments (16 by default, the maximum value can be 16 bits and is a power of two). Each segment is a thread-safe table of map elements. Increasing the number of segments will encourage modification operations to span multiple segments, reducing the likelihood of blocking at runtime.

  4. ConcurrencyLevel

    This parameter affects the memory card usage and the number of segments in the card.

    The number of segments will be chosen as the nearest power of two greater than concurrencyLevel. Lowering the concurrencyLevel makes it more likely that threads will block map segments when writing. Overestimation of the indicator leads to inefficient use of memory. If only one thread will modify the map, and the rest will read, it is recommended to use the value 1.

  5. Total

    So, the main advantages and implementation features ConcurrentHashMap:

    • hashmapThe map has an interaction interface similar to
    • Read operations do not require locks and are performed in parallel
    • Write operations can often also be performed in parallel without blocking
    • When creating, the required one is indicated concurrencyLevel, determined by reading and writing statistics
    • Map elements have a value valuedeclared asvolatile
    Source: How ConcurrentHashMap Works

9. What is the Lock class?

To control access to a shared resource, we can use locks as an alternative to the synchronized operator. The locking functionality is packaged in java.util.concurrent.locks. First, the thread tries to access the shared resource. If it is free, then a lock is placed on the thread. Once the work is completed, the lock on the shared resource is released. If the resource is not free and a lock is already placed on it, then the thread waits until this lock is released. Lock classes implement an interface Lockthat defines the following methods:
  • void lock():waits until the lock is acquired
  • boolean tryLock():tries to acquire a lock; if the lock is obtained, it returns true . If the lock is not acquired, it returns false . Unlike the method, lock()it does not wait to acquire a lock if one is not available
  • void unlock():removes the lock
  • Condition newCondition():returns the object Conditionthat is associated with the current lock
The organization of locking in the general case is quite simple: to obtain the lock, the method is called lock(), and after finishing working with shared resources, the method is called unlock(), which releases the lock. The object Conditionallows you to manage blocking. As a rule, to work with locks, a class ReentrantLockfrom the package is used. java.util.concurrent.locks.This class implements the interface Lock. Let's look at using the Java Lock API using a small program as an example: So, let's say we have a class Resourcewith a couple of thread-safe methods and methods where thread safety is not required.

public class Resource {
 
    public void doSomething(){
        // пусть здесь происходит работа с базой данных 
    }
     
    public void doLogging(){
        // потокобезопасность для логгирования нам не требуется
    }
}
Now let’s take a class that implements the interface Runnableand uses class methods Resource.

public class SynchronizedLockExample implements Runnable{
 
    // экземпляр класса Resource для работы с методами
    private Resource resource;
     
    public SynchronizedLockExample(Resource r){
        this.resource = r;
    }
     
    @Override
    public void run() {
        synchronized (resource) {
            resource.doSomething();
        }
        resource.doLogging();
    }
}
Now let's rewrite the above program using the Lock API instead of the synchronized.

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
 
// класс для работы с Lock API. Переписан с приведенной выше программы,
// но уже без использования ключевого слова synchronized
public class ConcurrencyLockExample implements Runnable{
 
    private Resource resource;
    private Lock lock;
     
    public ConcurrencyLockExample(Resource r){
        this.resource = r;
        this.lock = new ReentrantLock();
    }
     
    @Override
    public void run() {
        try {
            // лочим на 10 секунд
            if(lock.tryLock(10, TimeUnit.SECONDS)){
            resource.doSomething();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally{
            //убираем лок
            lock.unlock();
        }
        // Для логгирования не требуется потокобезопасность
        resource.doLogging();
    }
 
}
As you can see from the program, we use the method tryLock()to make sure that the thread only waits for a certain amount of time. If it does not obtain a lock on the object, it simply logs and exits. Another important point. You must use a block try-finallyto ensure that the lock will be released even if the method doSomething()throws an exception. Sources:

11. What is a mutex?

A mutex is a special object for synchronizing threads/processes. It can take two states - busy and free. To simplify, a mutex is a boolean variable that takes two values: busy (true) and free (false). When a thread wants exclusive ownership of an object, it marks its mutex as busy, and when it has finished working with it, it marks its mutex as free. A mutex is attached to every object in Java. Only the Java machine has direct access to the mutex. It is hidden from the programmer.

12. What is a monitor?

A monitor is a special mechanism (a piece of code) - an add-on over the mutex, which ensures correct operation with it. After all, it is not enough to mark that the object is busy; we must also ensure that other threads do not try to use the busy object. In Java, the monitor is implemented using the keyword synchronized. When we write a synchronized block, the Java compiler replaces it with three pieces of code:
  1. At the beginning of the block synchronized, code is added that marks the mutex as busy.
  2. At the end of the block, synchronizeda code is added that marks the mutex as free.
  3. Before the block, synchronizedcode is added that checks if the mutex is busy, then the thread must wait for it to be released.
Part 1
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION