Backend Development 28 min read

DJI Java Backend Interview Experience, Salary Insights, and Core Concurrency Knowledge

The article shares DJI's impressive compensation data, details a 50‑minute Java backend interview covering concurrency tools, locks, CountDownLatch, ConcurrentHashMap, Kafka ordering, zero‑copy, Spring AOP, filters vs. interceptors, and provides code examples and explanations for each concept.

IT Services Circle
IT Services Circle
IT Services Circle
DJI Java Backend Interview Experience, Salary Insights, and Core Concurrency Knowledge

Hello everyone, I am Xiao Lin.

Although DJI is not a Fortune 500 company nor a listed firm, it dominates the drone market with over 80% share and consistently reports strong profits, prompting many to wonder about its year‑end bonuses.

According to leaked information, the R&D department’s median year‑end bonus is about 180,000 CNY (some exceeding 250,000 CNY), while the Embedded department’s median is close to 200,000 CNY, with a few receiving more than five months of salary.

DJI’s overall salary packages for new graduates range from 350,000 to 500,000 CNY annually, comparable to major internet companies.

Other benefits include a monthly housing allowance of 1,500 CNY (first year) and 1,000 CNY (second year), a monthly internal e‑coin of 500 CNY, a 10 am–10 pm work schedule, and double weekends.

DJI Java Backend First‑Round Interview (50 minutes)

Opening Three Questions

Self‑introduction (focus on technology stack and projects).

What do you know about DJI? (demonstrate prior research).

Why this position? (match between role and personal interests).

Java Concurrency Tools

Tool

Applicable Scenario

Characteristics

synchronized

Simple synchronization or low‑contention environments

Simple syntax, JVM‑optimized (biased lock, lightweight lock)

ReentrantLock

High concurrency, need flexible control

Supports timeout, interrupt, fairness

ReadWriteLock

Read‑heavy shared‑resource access

Maximises read concurrency

StampedLock

Very high read‑performance requirements

Optimistic read lock reduces contention

Semaphore

Rate‑limiting or resource‑pool management

Configurable number of permits

Example of synchronized usage:

public synchronized void method() {
    // critical section
}

public static synchronized void staticMethod() {
    // critical section
}

private final Object lock = new Object();
public void someMethod() {
    synchronized (lock) {
        // critical section
    }
}

Example of ReentrantLock with a fair lock:

private final ReentrantLock lock = new ReentrantLock(true);

public void doWork() {
    lock.lock();
    try {
        // critical section
    } finally {
        lock.unlock();
    }
}

Example of ReentrantReadWriteLock :

private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();

public void readData() {
    rwLock.readLock().lock();
    try {
        // read shared data
    } finally {
        rwLock.readLock().unlock();
    }
}

public void writeData() {
    rwLock.writeLock().lock();
    try {
        // modify shared data
    } finally {
        rwLock.writeLock().unlock();
    }
}

Example of StampedLock with optimistic read:

private final StampedLock stampedLock = new StampedLock();

public double readOptimistic() {
    long stamp = stampedLock.tryOptimisticRead();
    double value = sharedValue;
    if (!stampedLock.validate(stamp)) {
        stamp = stampedLock.readLock();
        try {
            value = sharedValue;
        } finally {
            stampedLock.unlockRead(stamp);
        }
    }
    return value;
}

public void write() {
    long stamp = stampedLock.writeLock();
    try {
        // modify shared value
    } finally {
        stampedLock.unlockWrite(stamp);
    }
}

Example of Semaphore (single‑permit mutex):

Semaphore semaphore = new Semaphore(1);
semaphore.acquire();
try {
    // critical section
} finally {
    semaphore.release();
}

CountDownLatch

CountDownLatch (java.util.concurrent) allows one or more threads to wait until a set of operations performed by other threads completes.

Initialize with a count.

Threads call await() to block.

Other threads call countDown() to decrement the count.

When the count reaches zero, waiting threads are released.

Example:

public class MainThreadWaitExample {
    public static void main(String[] args) throws InterruptedException {
        int threadCount = 3;
        CountDownLatch latch = new CountDownLatch(threadCount);
        for (int i = 0; i < threadCount; i++) {
            new Thread(() -> {
                try {
                    System.out.println(Thread.currentThread().getName() + " executing task");
                    Thread.sleep(1000);
                    latch.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }, "Worker-" + i).start();
        }
        latch.await();
        System.out.println("All tasks completed");
    }
}

Common Concurrent Classes

Thread‑safe containers: ConcurrentHashMap , CopyOnWriteArrayList , CopyOnWriteArraySet , ConcurrentLinkedQueue , ConcurrentLinkedDeque .

Coordination utilities: CountDownLatch , CyclicBarrier , Semaphore .

Atomic classes: AtomicInteger , AtomicLong , AtomicBoolean .

Other utilities: ThreadLocal , lock interfaces ( ReentrantLock , ReentrantReadWriteLock , StampedLock ).

How ConcurrentHashMap Supports Concurrency

JDK 1.7 uses a segmented lock architecture: the map consists of an array of Segment objects (each a ReentrantLock ) and each segment holds an array of HashEntry linked‑list buckets. Only the segment containing the target bucket is locked, allowing other segments to be accessed concurrently.

JDK 1.8 replaces segments with a single array of bins that can be either a linked list or a red‑black tree. It uses volatile fields, CAS for lock‑free insertion when the bin is empty, and falls back to synchronized on the bin’s head node when contention occurs. This reduces lock granularity and improves performance, especially for large maps where the tree structure gives O(log n) lookup.

CAS Problems and Java’s Solution

CAS suffers from the ABA problem: a value may change from A→B→A, and a CAS check sees A again and assumes no change. Java mitigates this by attaching a version stamp or tag, e.g., AtomicStampedReference , which records both the value and a stamp.

AtomicStampedReference
ref = new AtomicStampedReference<>(100, 0);
// try to change value and stamp atomically
boolean success = ref.compareAndSet(100, 200, 0, 1); // succeeds only if value=100 and stamp=0

Java Lock Types

synchronized : built‑in keyword, simple syntax, no manual release.

ReentrantLock : implements Lock , supports re‑entrancy, interruptible lock acquisition, timeout, fairness.

ReentrantReadWriteLock : separate read and write locks; multiple readers can hold the read lock simultaneously.

Spin lock (implemented via CAS) – low‑level busy‑wait lock.

Frequently Used Locks

For simple synchronization, synchronized is convenient:

public class Counter {
    private int count = 0;
    public synchronized void increment() { count++; }
    public synchronized int getCount() { return count; }
}

When more control is needed, ReentrantLock offers interruptible and timed lock acquisition:

public class InterruptibleLockExample {
    private final ReentrantLock lock = new ReentrantLock();
    public void doWork() {
        try {
            lock.lockInterruptibly();
            // critical work
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            lock.unlock();
        }
    }
}

In read‑heavy scenarios, ReentrantReadWriteLock improves throughput:

public class Cache {
    private final Map
cache = new HashMap<>();
    private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
    private final ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock();
    private final ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock();
    public Object get(String key) {
        readLock.lock();
        try { return cache.get(key); }
        finally { readLock.unlock(); }
    }
    public void put(String key, Object value) {
        writeLock.lock();
        try { cache.put(key, value); }
        finally { writeLock.unlock(); }
    }
}

For simple counters, atomic classes based on CAS are ideal:

public class VisitorCounter {
    private AtomicInteger count = new AtomicInteger(0);
    public void increment() { count.incrementAndGet(); }
    public int getCount() { return count.get(); }
}

Spring AOP Overview

Spring AOP enables aspect‑oriented programming, separating cross‑cutting concerns (e.g., transactions, logging) from core business logic. Core concepts include AspectJ (aspect), Join point (method execution point), Advice (before/after/around), Pointcut (matching join points), Introduction, Weaving, and AOP proxy (JDK dynamic proxy or CGLIB).

Filter vs. Interceptor in Spring Boot

Feature

Filter

Interceptor

Specification

Servlet spec (

javax.servlet.Filter

)

Spring MVC (

org.springframework.web.servlet.HandlerInterceptor

)

Scope

Global – all requests and static resources

Controller layer – only Spring‑managed requests

Execution Order

Before Servlet processing

After DispatcherServlet, before/after controller method

DI Support

Cannot inject Spring beans directly

Can autowire Spring beans

Typical Use Cases

Global tasks – encoding, logging, security

Business‑level tasks – permission checks, parameter validation

Kafka Message Ordering

Kafka guarantees order only within a single partition. Producers achieve ordering by sending messages with the same key to the same partition (custom partitioner). Consumers must process a partition with a single thread to preserve order. Global ordering requires either a single partition (reducing parallelism) or business‑level sequencing.

Why Kafka Is Fast

Sequential disk writes minimise seek time.

Batching reduces network and I/O overhead.

Zero‑copy transfers data directly from kernel buffers to the network socket.

Optional compression reduces payload size.

Zero‑Copy in Java

Zero‑copy avoids copying data between user space (Java heap) and kernel space. Java’s FileChannel.transferTo / transferFrom invoke OS‑level mechanisms such as Linux’s sendfile , moving data directly from file buffers to socket buffers.

try (FileChannel source = FileChannel.open(Paths.get("input.txt"), READ);
     FileChannel target = FileChannel.open(Paths.get("output.txt"), WRITE)) {
    source.transferTo(0, source.size(), target);
}

Zero‑copy results in “zero‑CPU copy”: data moves from disk → kernel buffer → socket buffer → NIC via DMA without touching the Java heap.

Project‑Related Questions

What is the main role of Redis in the project?

What does Kafka handle in the project?

Issues encountered with Redis and their solutions.

Issues encountered with Kafka and their solutions.

Known point‑cloud formats.

Experience using DJI products for SLAM (visual, LiDAR, or fusion).

Key difficulties in the project.

Algorithm Exercises

Determine if two singly linked lists intersect.

Count the number of 1 bits in an integer.

Interview Impression

The interview felt well‑matched to my experience; the Java questions were deep, and I need to review some topics over the weekend. Unfortunately, I did not advance to the second round.

backendJavaconcurrencySpringKafkaInterviewDJI
IT Services Circle
Written by

IT Services Circle

Delivering cutting-edge internet insights and practical learning resources. We're a passionate and principled IT media platform.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.