Skip to content

Schedulers.io() reuses blocked threads #4230

Closed

Description

@csabakos-zz

Some actions are not interruptible. Since Schedulers.io() reuses threads after unsubscribe, a previous uninterruptible action might block execution of new actions, causing unexpected delays or in some cases, deadlocks.

Activity

  1. added a commit that references this issue on Jul 23, 2016
    e3f1926
  2. akarnokd commented on Jul 23, 2016

    @akarnokd
    Member

    Could you give an example of such non-interruptible blocking tasks?

  3. csabakos-zz commented on Jul 23, 2016

    @csabakos-zz
    Author

    @akarnokd A concrete example is in the test case that I added in #4231, but in general any task that is carelessly written (swallows InterruptedException, or busy looping, etc.) will trigger this issue.

    Example:

    int numClients = 0;
    for (Server s : servers) {
        try {
            numClients += s.queryNumClients();
        } catch (Exception e) {
            // Assume 0 clients
        }
    }
    return numClients;
    

    The InterruptedException caused by unsubscribe() is swallowed and if the next s.queryNumClients() blocks for minutes, then this will block the thread for minutes.

    What's worse is that this may even come from 3rd party code that also uses Schedulers.io() and cause extremely hard to debug problems.

  4. akarnokd commented on Jul 23, 2016

    @akarnokd
    Member

    I see. I'd consider the fix in #4231 as a temporary workaround because such tasks will keep blocking out threads (and leak resources). Generally, this is what newThread() is handy for: you get a new thread that can be blocked without the fear of reuse. Send such untrustwothy tasks to newThread() and the rest to io().

  5. csabakos-zz commented on Jul 23, 2016

    @csabakos-zz
    Author

    Absolutely, #4231 only prevents other tasks from being blocked by the misbehaving task, it does't prevent the thread (and potentially other resource) leaks.

    I believe the thread leak would be present with newThread() as well and there is not much we can do about this. There is Thread.stop() but it introduces more problems than it solves. Hopefully the misbehaving task will complete eventually and at that point the resources will be freed up. If it never completes then it's a lost thread and the resources are leaked permanently.

  6. added a commit that references this issue on Jul 23, 2016
    99abbf9
  7. Armaxis commented on Aug 18, 2016

    @Armaxis

    I happened to face this bug today, was using RxJava 1.1.2. After half an hour of debugging went to check for newer version, and guess what - first bug fix in release notes is exactly the one I was fighting. Pulled latest, everything works like a charm. Thank you guys!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions