Comments (18)
To be absolutely safe, create one instance of your STGroup
for each thread. In Java, you could use ThreadLocal<T>
to initialize your group on-demand (by overriding initialValue()
to load the group).
from stringtemplate4.
Thx for response. I know about ThreadLocal, but it has many issues while using in servlet container (memory leaks vs. war redeployment vs. somebody forgot to clear TL after http servlet request).
It would be nice to have immutable version of template after parsing/compiling from source code. Now I will try to preload template string to eliminate I/O operations.
from stringtemplate4.
Hi,
My work-around is to explicitly call getInstanceOf after creating the STGroupFile object. This will trigger the loading by a single thread (so, no race) and will populate the Map with the parsed CompiledST objects.
There's still the possibility that a later thread will not see the updated alreadyLoaded value and attempt to parse the file; however, that (while noisy) should be harmless, beyond a performance hit. Fixing that part in StringTemplate should be easy: just mark alreadyLoaded field member as volatile.
After initialising, getInstanceOf builds an ST object from the Map's CompiledST entry. The Map is thread-safe, so getInstanceOf should be fine and subsequent operations (setting the attributes and rendering the result) should operate within the ST object. I'm assuming (but haven't checked) that the CompiledST object is immutable.
I think there's a fair number of extra features that we're not using, so it's possible that other people will still suffer from race conditions, but I think we can get away without synchronising calls to getInstanceOf.
My advise (admittedly without having spent too much time thinking about it :) would be to get rid of the lazy load and either load on construction or (better) have an explicit 'load' or 'init' method that triggers the parsing of the templates. Attempts to use the STGroup before load/init should throw IllegalStateException (or similar), as would calling load/init more than once. It's the callers responsibility to call load/init correctly.
HTH,
Paul.
from stringtemplate4.
Also, In ST.java, there seems to be a couple of places that modifies impl object (which is a CompiledST instance).
- ST.java:inspect(...): impl.nativeGroup.setListener (probably this is only for debugging, so doesn't matter??)
- ST.java: add(String name, Object value) : calling impl.addArg():
Inside ST::addArg, it lazily creates a (synchronized) map, but potentially, two threads may each creates two instances of a map, and add args in each instance. Either the method should be synchronized (but then all the methods that access formalArguments should also be synchronized), or create the map instance in the constructor, before the CompiledST object is added to the templates map in the STGroup (so, don't do lazy initialization).
from stringtemplate4.
Hi. Thanks. I'll look into this when I get a chance.
On Mon, Aug 12, 2013 at 3:10 PM, seojiwon [email protected] wrote:
We use StringTemplate in multi-threaded configuration, where we create a
single STGroup instance, and multiple thread calls group.getInstanceOf and
render.The problem is we (sometimes) get "attribute XYZ isn't defined" error,
although the attribute XYZ (which is a map/dictionary template) is clearly
defined in an imported template.My guess is that StringTemplate has thread safety issue when (but not
limited to) a dictionary that is defined in an imported template file is
accessed.I went over the source code and found a few places that potentially have
thread safety issue.
Lazy initialization of STGroup (STGroupFile) object. STGroupFile calls
load() method lazily when necessary, so multiple thread can simultaneously
initialize the object (which may or may not be a problem). I think probably
load() should be synchronized.
2.CompiledST object is being modified after putting into the
synchronized 'templates' dictionary.
3.For example, in STGroup.java in defineRegion method
code.defineArgDefaultValueTemplates(this) and
code.defineImplicitlyDefinedTemplates(this) is called after the invocation
of the rawDefineTemplate method, which puts CompiledST object into the
synchronized map. Thus another thread may see an incomplete CompiledST
object.I did not check all the code, so there might be other places with thread
safety issues. I made STGroup.getInstanceOf, STGroup.getEmbeddedInstanceOf,
and ST.render to be synchronized with respect to the STGroup instance, and
the attribute error went away.
I suggest that those three methods to be synchronized; but also someone
should go over all the code and check if any other thread-safety issue is
there. Any code that does lazy evaluation should be examined for thread
safety.—
Reply to this email directly or view it on GitHubhttps://github.com//issues/61
.
Dictation in use. Please excuse homophones, malapropisms, and nonsense.
from stringtemplate4.
To reduce (but not eliminate) the chance of threading problems, I am marking a select group of methods as (Edit: I am deferring this issue. See below.) However, the thread safety of ST4 as a whole is not conclusively tested and is known to have problems in some cases. For a multi-threaded application, you should create one instance of your synchronized
for the 4.0.8 release.STGroup
for each thread in the application, and use the appropriate one for the current thread when rendering templates.
from stringtemplate4.
Hi, could you specifiy how to use ST to be safe with threads. I mean, is it safe to create STGroup instance, call load() and than share it among threads (in webapp env, considering IO ops)? And after that when I want to call template just call STGroup.getInstanceOf(...). Thx
from stringtemplate4.
Once it's loaded, it shouldn't change at all for getInstanceOf, should it? W/o looking at code, it seems safe. Adding in multiple threads would be bad.
from stringtemplate4.
Unfortunately, I don't have the time to rigorously evaluate the thread safety of ST. There are a few cases that are clearly not safe for multithreaded use, even after the group is loaded. Based on this, I wouldn't assume that any template instances created by a single STGroup
can be used concurrently in an application.
I'll work to implement a thread-safe version of ST4, but it won't appear before version 4.1 at minimum.
from stringtemplate4.
For release 4.0.8, I'm going to leave the synchronization code as-is.
from stringtemplate4.
Ok, thx for info.
from stringtemplate4.
I found a problem that seems to be from a race-condition from the lazy loading.
What I believe is happening is that more than one thread calling getInstanceOf (in STGroup) concurrently. Within STGroupFile, the alreadyLoaded field member controls the lazy load. This is not declared volatile, so the visibility between different threads after update is not guaranteed, resulting in potential multiple initialisations -- while a problem, I don't believe this causes the problem I'm seeing. Rather, the problem seems to be because alreadyLoaded is set to true before the initialisation completes.
Consider two threads calling getInstanceOf at the same time. The first race is to see whether both threads or just one will parse the file. Assume one parses the file and the other doesn't (believing the file is already loaded), the next race starts. The thread parsing the file will attempt to put the CompiledST into the templates Map, while the thread that doesn't parse the file will attempt to put NOT_FOUND_ST constant into the Map.
Since the thread that is parsing the file will likely take longer, lets say the other thread wins the race and puts the NOT_FOUND_ST into the Map. After parsing, the thread will attempt to put the CompiledST into the Map, which will fail with a "redefinition of template" error message.
The thread that parsed the file should return a non-null value getInstanceOf, but all other attempts for this template will return null.
from stringtemplate4.
Hi. I believe this is similar to another issue related to thread safety. I believe that it is not safe to access the same template group from multiple threads without synchronizing the access yourself. I don't think we've been particularly clear about that. Sorry. I'm leaving this open because it might be something we can easily fix. In the meantime, can you put a synchronized block around get instance of?
from stringtemplate4.
Potential solution:
HTH,
Paul.
from stringtemplate4.
@paulmillar For StringTemplate 4.0.x, you should not use the same STGroup
instance in multiple threads concurrently. You could either create an STGroup
instance for each thread that needs one (each instance tied to a specific thread), or use an object pool capable of assigning an STGroup
instance to a particular thread, and then "returning" it to the object pool where it is no longer associated with a particular thread (improving performance for applications that do not use dedicated long-running render threads).
The concurrency issues need to be thoroughly evaluated throughout ST4 before I'm comfortable changing this recommendation, and implemented in a manner designed with concurrent rendering in mind from the start. Your comments definitely help with this analysis, but they are likely incomplete so users in other scenarios could still hit unexpected behavior when using ST4 in concurrent applications.
from stringtemplate4.
Hi Paul, sorry for the long delay. Thanks very much for raising this issue and your potential solution. As Sam says, however, I'm a bit nervous with the addition of synchronized. I'm not convinced it will solve the problem without looking at it very carefully. It's often the case that there are multiple methods that need to execute as a transaction rather than simply providing two methods from executing at the same time. A simple solution is for you to create a proxy object that locks. I can usually get intellij to generate a proxy object that delegates. Consequently, I'm closing this issue. thanks.
from stringtemplate4.
Just as a side node - you need an threadsafe singleton mechanism, to prevent multithreading issues while initializing the STGroup. I've chosen Google Guava's micro caching Suppliers.memoize
.
By the way - I did not encounter problems afterwards sharing the intitiatlized STGroup beteween threads.
Supplier<STGroup> stGroupSupplier = Suppliers.memoize(
new Supplier<STGroup>() {
@Override
public STGroup get() {
try {
return new STGroup(...)
}
}
}
then
stGroupSupplier.get()
from the Guava javadoc: "The returned supplier is thread-safe. The delegate's get() method will be invoked at most once."
from stringtemplate4.
@hartmut27 The problem here is the lazy loading( and paring) of the template file, not the initializing of STGroup. So your code may need to include the loading of template file to work.
from stringtemplate4.
Related Issues (20)
- CDATA section HOT 2
- Loading template group from STGroupDir in app running on Tomcat 8 fails HOT 12
- How to pass arguments for indirect template call? HOT 3
- Incorrect indentation HOT 4
- Integrating stringtemplate4 into OSS-Fuzz HOT 1
- ST4-testjar not found HOT 9
- Use Class.getDeclaredField instead of Class.getField HOT 2
- Separator not emitted for nulls until a value is hit HOT 4
- Multiple special characters in a single <...> does not work as documented HOT 1
- You cannot use i as variable name HOT 3
- Should support coercing the (non)emptiness of a Map or Collection to a Boolean for conditionals of the form `<if(a.p)>` where `p` is a Collection or Map HOT 2
- Comparison with python based template engines like jinja2/mustache
- Looking for code samples cited in this article: Language Translation Using ANTLR and StringTemplate HOT 4
- Support for Java records HOT 2
- Test failures like org.junit.ComparisonFailure: expected:<...etime: 7/5/05, 12:00[ ]AM> but was:<...etime: 7/5/05, 12:00[ ]AM>
- Successful test prints error
- Does it support Custom Function?
- Help newbies with ANTLR dependencies
- correct StackOverflowEerror from rendering `java.nio.Path` HOT 1
- Zip map wrongly requires i0 and i in the argument list
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from stringtemplate4.