简体   繁体   中英

Deadlock implementation doesn't work without Thread.sleep

I'm trying to understand deadlocks and accordingly attempting to create an implementation of deadlock. The idea is to create a simulation of cyclic locking. Here's my Runnable implementation:

public class WorkDelegator implements Runnable {

private static final Logger LOGGER = Logger.getGlobal();

WorkDelegator workDelegatorSupplier;
private final String name;

public WorkDelegator(String name) {
    this.name = name;
}

public void setWorkDelegatorSupplier(WorkDelegator workDelegatorSupplier) {
    this.workDelegatorSupplier = workDelegatorSupplier;
}

public void delegate(){

    synchronized (workDelegatorSupplier) {
//            try {
//                Thread.sleep(300);
//            } catch (InterruptedException e) {
//                LOGGER.warning("InterruptedException in Task " + name);
//            }
        workDelegatorSupplier.delegate();
    }
    LOGGER.info("task delegated from " + name + "to " + workDelegatorSupplier);
}

@Override
public void run() {
    LOGGER.info(this + " is trying to delegate task to " + workDelegatorSupplier);
    delegate();
}
}

A bunch of WorkDelegator instances cyclically delegating work on each other by calling delegate void. The point is that it works properly if commented out code is executing too, but why I get StackOverflowError without Thread sleeping?

PS - Delegator Factory class:

public class WorkDelegatorFactory {

public List<WorkDelegator> getDelegatorsList(int size) {

    List<WorkDelegator> workDelegatorList = new ArrayList<>();
    for (int i = 0; i < size ; i++) {
        workDelegatorList.add(new WorkDelegator(String.valueOf(i)));
    }
    WorkDelegator firstDelegator = workDelegatorList.get(0);
    WorkDelegator lastDelegator = workDelegatorList.get(size-1);
    lastDelegator.setWorkDelegatorSupplier(firstDelegator);
    for (int i = 0; i < size-1; i++) {
        workDelegatorList.get(i).setWorkDelegatorSupplier(workDelegatorList.get(i+1));
    }
    return workDelegatorList;
}
}

Without sleep the first thread to launch can do a lot of recursive calls before the others start. This allows them to grab enough of the synchronization locks to continue indefinitely and eventually run out of stack depth. Other threads started arrive too late to grab their first synchronization lock and just sit idle.

With the sleep each thread can only grab one synchronization lock and no thread can get so far ahead that it can loop.

What you are seeing is the one of the hard parts of concurrent programming: you know the sequence in each thread but not where each thread is in relation to the others.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM