4

I have 2 threads each with a Threadlocal list named threadLocal that will both spawn child threads. I want the child threads to be able to modify the parent's threadLocal.

I have tried passing in the parent itself to the child so that it can call parent.threadLocal.get().add(x) but this causes a null pointer exception. When the parent calls threadLocal.get().add(x) it is able to add x to the list just fine.

I know the issue is with the .add(x) because having the child just call .get() does not cause an exception. I also tried passing the threadLocal itself to the child and that gives the same error.

Is there a way to do this?

CrazyBurrito
  • 105
  • 3
  • 8
  • What is the purpose of making the variable thread local if you need to access it from multiple threads? – Eranda Apr 24 '15 at 22:38
  • 1
    possible duplicate of [How to continue object from ThreadLocal in child thread?](http://stackoverflow.com/questions/6327913/how-to-continue-object-from-threadlocal-in-child-thread) – CupawnTae Apr 24 '15 at 22:40
  • Another possibility would be to invoke, from the children threads, a parent's method that would modify its own ThreadLocal list. – Felipe Martins Melo Apr 24 '15 at 22:45
  • @Eranda The reason it needs to be a Threadlocal is because there are multiple parents that need to have their own list – CrazyBurrito Apr 24 '15 at 22:46
  • @FelipeMartinsMelo the parent thread doesn't have methods, the object has methods. If a child thread invokes a method, it runs on that child thread, not on the parent thread, and so it will get the child's ThreadLocal, not the parent's – CupawnTae Apr 24 '15 at 22:49
  • Then you should use InheritableThreadLocal instead ThreadLocal as suggested in @CupawnTae 's link. – Eranda Apr 24 '15 at 22:56
  • @Eranda We can't use InheritableThreadLocal because the parent needs to be able to see the modifications to the variable that the children have made. – CrazyBurrito Apr 24 '15 at 23:06
  • @CrazyBurrito you don't have to change the variable to modify the list. Think of it like the parent lending her car to the child. The child can fill the car full of junk, and the parent will discover the junk. But the child can't buy a different car and tell the parent "now this is your car" – CupawnTae Apr 24 '15 at 23:15

1 Answers1

6

You can retrieve the list in the parent and pass that to the child, or use InheritableThreadLocal.

Using InheritableThreadLocal means the value is copied to any child threads.

Note that in either case, you can't change the value of the parent's ThreadLocal variable, but you can mutate the object the variable refers to. In your case calling .add(...) on the list will work fine, as long as you handle concurrency correctly, e.g. by using CopyOnWriteArrayList

CupawnTae
  • 14,192
  • 3
  • 29
  • 60
  • Is there no way for a child to modify its parent's variable? – CrazyBurrito Apr 24 '15 at 22:48
  • @CrazyBurrito Not directly, but it's easy to wrap a variable in an object and mutate the object instead. E.g. you could have a single-element array that holds the value, or a custom 'holder' object. Then you just change the value in the array or holder and the change is visible to the parent. Make sure to deal with concurrency issues though if doing something like that. – CupawnTae Apr 24 '15 at 22:52
  • So let me see if I understand you. So I could have the parent create a Threadlocal array with a list as the only element. Then I pass the array to the child and it will be able to modify the list inside it? – CrazyBurrito Apr 24 '15 at 23:00
  • @CrazyBurrito if you just want to modify a list, you don't need to wrap it. You can just do `list.add(item)` - this doesn't change the variable, it mutates the `List` object. The parent's variable still points to the same list, but now the list has changed. That's all fine. What you can't do is point the parent's ThreadLocal variable to a completely different list. – CupawnTae Apr 24 '15 at 23:04
  • *However*, as I mentioned you have to be careful of concurrency issues, e.g. by using a CopyOnWriteArrayList - which is worth mentioning in the answer, edited – CupawnTae Apr 24 '15 at 23:07
  • But as I said in the question trying to call .add(x) from the child gives a null pointer exception. I believe that calling parent.list.get() is returning null because it doesn't recognize the threadlocal as having been set by the parent. – CrazyBurrito Apr 24 '15 at 23:11
  • oh and don't use `parent.threadLocal.get()`, just use `threadLocal.get()` – CupawnTae Apr 24 '15 at 23:19
  • If I use inhertiablethreadlocal are the changes that the child made immediately reflected in the parent? And most importantly will the other children be able to see those changes? – CrazyBurrito Apr 24 '15 at 23:20
  • yes, as long as you use either use a concurrency-friendly list like CopyOnWriteArrayList (see link in answer) or deal with concurrency in other ways – CupawnTae Apr 24 '15 at 23:22
  • Ok I just tested it out and it is working. Thank you very much or your help. – CrazyBurrito Apr 24 '15 at 23:38