0

I'm trying to figure out how to cancel a task in a ThreadPool if a new tasks comes along that supersedes it. I have some classes similar to this:

class RenderableThing {
    private val lock = ReentrantLock()
    fun lock(interrupt: Boolean) {
        if (lock.isLocked && interrupt) {
            // How do I interrupt the thread that has the lock?
        }
        lock.lock()
    }
    fun unlock() = lock.unlock()

    fun cache() = Cached()
    inner class Cached()
}

class BackgroundStuff(threads: Int) {
    val pool = Executors.newFixedThreadPool(threads)!!

    fun doBackgroundStuff(thing: RenderableThing): Future<Stuff> {
        val cache = thing.cache()
        return pool.submit {
            try {
                thing.lock()
                // Do long running I/O task on cache
            } finally {
                thing.unlock()
            }
        }
    }
}

However, if the same RenderableThing gets submitted to doBackgroundStuff (a change was made and needs to be saved to disk), I would like to be able to able to cancel the Future of the previous submission (since it's now out of date and will be overwritten, there's no reason to wait for it to finish anymore). The problem is, the locking is taking place inside the future that doesn't exist yet.

I know you're never supposed to force kill a locked thread (I don't even know how since it's a ReentrantLock), so what is the proper way to do this?

Edit: My question is different from this one as I don't have access to the future to cancel it (the lock isn't put in place till the ThreadPool picks it up, and by that point the thing could have been submitted multiple times, and I don't know which would own the lock). If I did it would be a piece of cake (the code to handle interruption is already in place). How should I change my code to get a reference to the future (or even the thread) that owns the lock?

Community
  • 1
  • 1
Ruckus T-Boom
  • 4,566
  • 1
  • 28
  • 42

1 Answers1

0

I'm just wondering if this piece of code works:

//...
fun doBackgroundStuff(thing: RenderableThing): Future<Stuff> {
    L.L.get(thing)?.cancel(true)
    val cache = thing.cache()
    val f = pool.submit {
        try {
            thing.lock()
            // Do long running I/O task on cache
        } finally {
            thing.unlock()
        }
    }
    L.L.put(thing, f)
    return f
}
//...

object L {
    val L: IdentityHashMap<RenderableThing, Future<Stuff>>  ? = IdentityHashMap<>()
}
glee8e
  • 6,180
  • 4
  • 31
  • 51
  • No, that would keep all but one `RenderableThing`, where I only want to remove it if it is the same one. I already tried similar code (but putting it in `RenderableThing` to solve this issue), but ran into issues since the delayed locking means anything could have happened in the meantime. – Ruckus T-Boom Nov 24 '16 at 14:16
  • Actually, Modifying your code to mix it with what I was doing earlier might just solve my problem. Let me run some tests. – Ruckus T-Boom Nov 24 '16 at 14:32
  • @RuckusT-Boom Updated. – glee8e Nov 24 '16 at 14:59