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

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

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

6. What is cancarensi?

Concurrency is a class library in Java that has collected special classes that are optimized to work with multiple threads. These classes are collected in the java.util.concurrent. They can be schematically divided by functionality as follows: Level 26. Answers to interview questions on the topic of the level.  Part 2. Questions 6-9, 11-12 - 2Concurrent Collections - a set of collections that work more efficiently in a multi-threaded environment than the 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 multithreading support. Non-blocking queues are designed for speed and work without blocking threads. Blocking queues are used when it is necessary to "slow down" the "Producer" or "Consumer" threads if some conditions are not met, for example, the queue is empty or full, or there is no free "Consumer" 'a. Synchronizers are utility utilities for synchronizing threads. They are a powerful weapon in "parallel" computing. Executors - contains excellent frameworks for creating thread pools, scheduling the work of asynchronous tasks with obtaining results. Locks - is an alternative and more flexible thread synchronization mechanisms compared to the basic ones synchronized,wait, notify, notifyAll. Atomics are classes that support atomic operations on primitives and references. Source:

7. What classes from Cancarensi do you know?

The answer to this question is well stated in this article . I don’t see the point of reprinting all of it here, so I’ll give descriptions of only those classes that I had the honor to casually get acquainted with. ConcurrentHashMap<K, V> — Unlike Hashtableblocks synhronizedon HashMap, data is presented as segments broken down by key hashs. As a result, data access is locked by segments, not by one object. In addition, iterators represent data for a specific slice of time and do not throw ConcurrentModificationException. AtomicBoolean, AtomicInteger, AtomicLong, AtomicIntegerArray, AtomicLongArray - What if the class needs to synchronize access to one simple variable of type int? You can use structures withsynchronized, and when using atomic operations set/get, also works volatile. But you can do even better by using the new 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 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 during 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 related 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);
    }

    What is the need to complicate the hash function? The tables in a hash map are a power of two in length. For hash codes whose binary representations do not differ in the minor and major positions, we will have collisions. Complicating 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 represent a power of two). Each segment is a thread-safe table of map elements. Increasing the number of segments will encourage modification operations to affect different segments, which will reduce the chance of blocking during execution.

  4. ConcurrencyLevel

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

    The number of shards will be chosen as the nearest power of two greater than concurrencyLevel. Lowering the concurrencyLevel leads to the fact that threads are more likely to 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:

    • The map has a similar hashmapinteraction interface
    • Read operations do not require locks and are performed in parallel
    • Write operations can often also run in parallel without blocking.
    • When creating, the required is specified concurrencyLevel, determined by read and write statistics
    • Map elements have a value valuedeclared asvolatile
    Source: How ConcurrentHashMap works

9. What is the Lock class?

As an alternative to the synchronized statement, we can use locks to control access to a shared resource. 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 on it. When the work is completed, the lock on the share is released. If the resource is not free and the lock is already 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 a lock is acquired
  • boolean tryLock():tries to acquire the lock, if the lock is acquired then returns true . If the lock is not acquired, it returns false . Unlike a method, lock()it does not wait to acquire a lock if it is not available.
  • void unlock():removes the lock
  • Condition newCondition():returns the object Conditionthat is associated with the current lock
The organization of a lock is generally quite simple: to obtain a lock, the method is called lock(), and after the work with shared resources is finished, the method is called unlock(), which releases the lock. The object Conditionallows you to control the lock. ReentrantLockAs a rule, a class from the package is used to work with locks. java.util.concurrent.locks.This class implements the Lock. Let's consider using the Java Lock API on the example of a small program: 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(){
        // потокобезопасность для логгирования нам не требуется
    }
}
And now we take a class that implements the interface Runnableand uses the methods of the class 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 acquire a lock on the object, then it simply logs and exits. Another important point. You must use a block try-finallyto ensure that the lock is 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 to have exclusive ownership of some object, it marks its mutex as occupied, 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 a mutex that ensures proper work with it. After all, it is not enough to mark that the object is busy, you must also ensure that other threads do not try to use the busy object. In Java, a monitor is implemented using the 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, synchronizedcode is added that marks the mutex as free.
  3. Before the block, synchronizeda code is added that looks, 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