https://github.com/peter-gergely-horvath/threadconfined
ThreadConfinement: enforce thread confinement of objects by wrapping them into guardian proxies
https://github.com/peter-gergely-horvath/threadconfined
Last synced: 4 months ago
JSON representation
ThreadConfinement: enforce thread confinement of objects by wrapping them into guardian proxies
- Host: GitHub
- URL: https://github.com/peter-gergely-horvath/threadconfined
- Owner: peter-gergely-horvath
- License: apache-2.0
- Created: 2017-04-18T19:56:29.000Z (about 8 years ago)
- Default Branch: master
- Last Pushed: 2017-04-18T20:28:20.000Z (about 8 years ago)
- Last Synced: 2025-01-08T21:16:37.753Z (5 months ago)
- Language: Java
- Size: 15.6 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Thread Confinement
Thread Confinement - that an object can only be accessed by a single thread - is
an important concept in a multi-threaded application. Finding cases where an
object should be confined to a thread, but it is actually accessed from another
can be tricky.This library provides support for enforcing thread confinement by wrapping objects
into proxies that fail-fast when accessed from a different thread by throwning an
exception or generating a log message.## Sample: Thread Confinement guardian in action
The following sample application tries to access `guardedHashSet` from a
different thread it was created from. As a result it will exit with an
exception stack trace similar to the one below:
```
Exception in thread "main" java.lang.RuntimeException: java.util.concurrent.ExecutionException: com.github.threadconfined.ThreadConfinementViolationException: Illegal access from thread 'Thread[pool-1-thread-1,5,main]': object should only be accessed from 'Thread[main,5,main]'
at com.github.threadconfined.SampleApp.launderThrowable(SampleApp.java:40)
at com.github.threadconfined.SampleApp.main(SampleApp.java:30)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
Caused by: java.util.concurrent.ExecutionException: com.github.threadconfined.ThreadConfinementViolationException: Illegal access from thread 'Thread[pool-1-thread-1,5,main]': object should only be accessed from 'Thread[main,5,main]'
at java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.util.concurrent.FutureTask.get(FutureTask.java:192)
at com.github.threadconfined.SampleApp.main(SampleApp.java:25)
... 5 more
Caused by: com.github.threadconfined.ThreadConfinementViolationException: Illegal access from thread 'Thread[pool-1-thread-1,5,main]': object should only be accessed from 'Thread[main,5,main]'
at com.github.threadconfined.ThreadConfinement$ViolationAction$2.onAccessFromUnexpectedThread(ThreadConfinement.java:85)
at com.github.threadconfined.ThreadConfinementGuardianProxy.invoke(ThreadConfinementGuardianProxy.java:32)
at org.javassist.tmp.java.util.HashSet_$$_javassist_0.contains(HashSet_$$_javassist_0.java)
at com.github.threadconfined.SampleApp.lambda$main$0(SampleApp.java:22)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
```
```java
package sample;import com.github.threadconfined.*;
import java.util.HashSet;
import java.util.concurrent.*;public class SampleApp {
public static void main(String[] args) {
try {
final HashSet guardedHashSet = ThreadConfinement.threadConfined(new HashSet());
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future futureResult = executorService.submit(() ->
/*
Illegal Access: guardedHashSet was created from main thread,
but is accessed from ExecutorService thread!
*/
guardedHashSet.contains("Foobar"));futureResult.get();
} catch (InterruptedException e) {
// Unexpected case: interruption -- quit application
} catch (ExecutionException e) {
throw launderThrowable(e);
}
}private static RuntimeException launderThrowable(Throwable t) {
if (t instanceof java.lang.Error) {
throw (java.lang.Error) t;
} else if (t instanceof RuntimeException) {
return (RuntimeException) t;
} else {
return new RuntimeException(t);
}}
}
```