Lenovo Backend Interview Secrets: Deadlocks, DNS, TLS & Java ArrayList
The article examines Lenovo’s 2023 graduate hiring salaries across cities, roles, and education levels, then shares a recent backend interview experience, detailing questions on deadlocks, networking layers, DNS resolution, TLS handshakes, common data structures, and Java’s ArrayList implementation, offering practical insights and recommendations.
Lenovo Backend Interview (First Round)
1. Deadlock and its causes
A deadlock occurs only when the following four conditions are simultaneously satisfied:
Mutual exclusion : multiple threads cannot use the same resource at the same time.
Hold and wait : a thread holding one resource requests another resource while still holding the first.
No preemption : a resource cannot be forcibly taken from a thread until the thread releases it voluntarily.
Circular wait : the waiting threads form a circular chain of resource requests.
2. How to avoid deadlock
The simplest way is to break any one of the four conditions. The most practical technique is resource ordering , which eliminates the circular‑wait condition by enforcing a consistent acquisition order for all threads.
3. IP protocol layer
The IP protocol belongs to the Network layer of the OSI/TCP‑IP model.
4. Protocol for domain name to IP translation
Domain names are translated to IP addresses using the DNS (Domain Name System) protocol.
5. DNS resolution process
The client sends a DNS query for www.server.com to the configured local DNS server.
If the local server’s cache contains the record, it returns the IP address; otherwise it queries the root DNS server.
The root server points the client to the .com top‑level DNS server.
The .com server returns the address of the authoritative DNS server for server.com.
The authoritative server looks up the exact record and returns the IP address to the local DNS server.
The local DNS server finally returns the IP address to the client, which can now connect to the target host.
6. Modifying the hosts file
The hosts file binds domain names to specific IP addresses locally, bypassing external DNS resolution. For example, adding the line 192.168.1.100 www.test.com lets a developer test a website before it is publicly deployed.
7. TLS handshake process (RSA‑based)
TLS First Handshake
ClientHello : client sends supported TLS version, a random number ( ClientRandom), and a list of cipher suites.
TLS Second Handshake
ServerHello : server replies with the selected TLS version, its own random number ( ServerRandom), the chosen cipher suite, and its digital certificate.
TLS Third Handshake
Client verifies the server certificate, extracts the server’s public key, encrypts a pre‑master secret with it, and sends the encrypted secret together with a “ChangeCipherSpec” notification.
TLS Fourth Handshake
Server decrypts the pre‑master secret, derives the session key, sends its own “ChangeCipherSpec” and “Finished” messages, completing the handshake. Subsequent communication uses the derived session key while the underlying protocol remains HTTP.
8. Common data structures (quick overview)
Array – contiguous memory, O(1) random access, O(n) insertion/deletion.
Linked list – nodes stored non‑contiguously, fast insertion/deletion, slower random access.
Stack – LIFO, only top‑element operations.
Queue – FIFO, enqueue at tail and dequeue at head.
Tree – hierarchical, suitable for representing nested relationships.
9. Java ArrayList
ArrayListis a dynamic array implementation in the java.util package that implements the List interface. It stores elements in an internal Object[] array and automatically expands when capacity is exceeded.
Dynamic expansion : when the number of elements reaches the current capacity, the array grows (default new capacity = old capacity × 1.5). Initial capacity can be set explicitly via new ArrayList<>(initialCapacity).
Ordered and allows duplicates : elements are kept in insertion order and duplicate (including null) values are permitted.
Not thread‑safe : concurrent modifications can corrupt internal state; thread‑safe alternatives include Collections.synchronizedList or CopyOnWriteArrayList.
Fast random access : get(int index) runs in O(1); insertion/deletion (especially in the middle) requires shifting elements and runs in O(n).
10. ArrayList insertion process
ArrayList relies on two internal fields: size – current number of stored elements. capacity – length of the backing Object[] array.
Tail insertion ( add(E e) )
public boolean add(E e) {
// Step 1: ensure there is room for size+1 elements
ensureCapacityInternal(size + 1);
// Step 2: store the element at the end and increment size
elementData[size++] = e;
return true;
}Steps:
Call ensureCapacityInternal(size+1) to check whether the backing array needs to grow. If the array is null, a default capacity (10) is allocated; if size+1 exceeds the current length, a new array of size oldCapacity + (oldCapacity>>1) (≈1.5×) is created and the old elements are copied.
Assign the new element to elementData[size] and then increment size.
Insertion at a specific index ( add(int index, E element) )
public void add(int index, E element) {
// Step 1: validate index
if (index > size || index < 0) {
throw new IndexOutOfBoundsException();
}
// Step 2: ensure capacity
ensureCapacityInternal(size + 1);
// Step 3: shift subsequent elements right by one position
System.arraycopy(elementData, index, elementData, index + 1, size - index);
// Step 4: insert the new element and update size
elementData[index] = element;
size++;
}Steps:
Check that index is within 0..size (index == size is equivalent to tail insertion).
Perform the same capacity check as in tail insertion.
Use System.arraycopy to move the block elementData[index .. size‑1] one position to the right, creating a free slot at index.
Store the new element at elementData[index] and increment size.
11. Thread safety of ArrayList
ArrayList is not thread‑safe. All mutating methods operate on shared fields without synchronization, leading to race conditions such as: size++ is non‑atomic, causing lost updates or overwriting of elements.
Concurrent writes to elementData can corrupt the array.
The internal modCount may become inconsistent, triggering ConcurrentModificationException. size lacks the volatile modifier, so updates may not be visible across threads.
Example of a race during tail insertion:
// Thread A
ensureCapacityInternal(size + 1);
elementData[size++] = e1; // writes to slot 5
// Thread B (interleaved)
ensureCapacityInternal(size + 1);
elementData[size++] = e2; // also writes to slot 5Possible outcomes:
One element overwrites the other, losing data.
If the array is already full, both threads may think there is space, leading to an ArrayIndexOutOfBoundsException.
To achieve thread safety, wrap the list with Collections.synchronizedList or use a concurrent implementation such as CopyOnWriteArrayList.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
IT Services Circle
Delivering cutting-edge internet insights and practical learning resources. We're a passionate and principled IT media platform.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
