Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 8487243
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 10, 20262026-06-10T21:10:56+00:00 2026-06-10T21:10:56+00:00

I’ve experience a really painful java learning curve and still a newbie. I’m designing

  • 0

I’ve experience a really painful java learning curve and still a newbie.

I’m designing a low-level library class, in the future it possibly can be used in an multi-threading environment or just in a single thread. I have no idea of that.

I can let user of this class to synchronize from outside. But that will be much more inefficient than provide a thread-safety version.

This is p-code.

Class Example{
    public int checkAndProcess(){
        WriteLock writeLock=this.getWriteLock();
        ReadLock readLock=new ReadLock(writeLock);
        int a;
        try{
            lockManager.lock(readLock);
            a=readSomething();
        }finally{
            lockManager.release(readLock);
        }
        if(a!=null){
            return a;
        }
        try{
            lockManager.lock(writeLock);
            a=doSomeProcessing();
        }finally{
            lockManager.release(writeLock);
        }
        return a;
    }
}

It will be much faster than synchronize from outside because readlock doesn’t block. It’s create and garbage-collected in every method call.

Problem:

Overhead. WriteLock is pretty complex, ReadLock is cheap and simple but it’s created in every method call(and possibly multiple), so still an overhead.

Should I provide a thread-safety version of every such class? Every open source library doesn’t do that. But if I don’t provide it, let user synchronize from outside, performance will be lowered.

Or is there any better way ?

Edit:

Should I split it?

Split it into a stateless processor and a store, and let user to create readLock/writeLock to lock? If I do that, the store will be totally designed for the processor, doesn’t have much meaning for other class, and the library will be quickly boomed by those things.

This is my real code. You can ignore it if you don’t like.

package lazycatTools.runtime;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;

import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.jobs.Job;
import org.osgi.framework.AllServiceListener;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceEvent;
import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceReference;

public class DynamicServiceTracker {

    private final HashMap<Long,Object> _serviceCache;
    private final HashMap<String,Long> _keyCache;

    private final MultiResourceSchedulingRule _writeLock;

    private final ServiceListener _tracker;

    private final BundleContext _context;

    public DynamicServiceTracker(BundleContext context){
        Assert.isLegal(context!=null);
        _serviceCache=new HashMap<Long,Object>();
        _keyCache=new HashMap<String,Long>();
        HashSet<Object> lockResource=new HashSet<Object>(4);
        lockResource.add(_serviceCache);
        lockResource.add(_keyCache);
        _writeLock=new MultiResourceSchedulingRule<DynamicServiceTracker,Object>(this,lockResource);
        _context=context;
        _tracker=new AllServiceListener(){

            @Override
            public void serviceChanged(ServiceEvent event) {
                if(event.getType()==ServiceEvent.UNREGISTERING){
                    ServiceReference<?> ref=event.getServiceReference();
                    Long sid=(Long)ref.getProperty(Constants.SERVICE_ID);
                    String[] classes=(String[])ref.getProperty(Constants.OBJECTCLASS);
                    boolean ungetService=false;
                    try{
                        Job.getJobManager().beginRule(_writeLock, null);
                        for(String clazz : classes){
                            if(_keyCache.get(clazz)==sid){
                                _keyCache.remove(clazz);
                                break;
                            }
                        }
                        if(_serviceCache.containsKey(sid)){
                            _serviceCache.remove(sid);
                            ungetService=true;
                        }
                    }finally{
                        Job.getJobManager().endRule(_writeLock);
                    }
                    if(ungetService){
                        //The order of ungetting a serviceReference is not important
                        _context.ungetService(ref);
                    }
                    SharedSchedulingRule readLock=new SharedSchedulingRule(_writeLock);
                    try{
                        Job.getJobManager().beginRule(readLock, null);
                        if(_serviceCache.size()==0){
                            _context.removeServiceListener(_tracker);
                        }
                    }finally{
                        Job.getJobManager().endRule(readLock);
                    }
                }
            }
        };
    }

    public Object getService(String clazz) throws Exception{
        Object cachedService=null;
        Long key;
        SharedSchedulingRule readLock=new SharedSchedulingRule(_writeLock);
        try{
            Job.getJobManager().beginRule(readLock, null);
            key=_keyCache.get(clazz);
            if(key!=null){
                cachedService=_serviceCache.get(key);
            }
        }finally{
            Job.getJobManager().endRule(readLock);
        }
        if(cachedService!=null){
            return cachedService;
        }
        ServiceReference<?> ref=_context.getServiceReference(clazz);
        Long sid=(Long)ref.getProperty(Constants.SERVICE_ID);
        Object newService=_context.getService(ref);
        try{
            Job.getJobManager().beginRule(_writeLock, null);
            key=_keyCache.get(clazz);
            if(key!=null){
                cachedService=_serviceCache.get(key);
            }else{
                _keyCache.put(clazz,sid);
                _serviceCache.put(sid, newService);
            }
        }finally{
            Job.getJobManager().endRule(_writeLock);
        }

        if(cachedService!=null){
            _context.ungetService(ref);
            return cachedService;
        }else{
            _context.addServiceListener(_tracker);
            return newService;
        }
    }

    public <Type> Type getService(Class<Type> clazz){
        Object cachedService=null;
        Long key;
        SharedSchedulingRule readLock=new SharedSchedulingRule(_writeLock);
        try{
            Job.getJobManager().beginRule(readLock, null);
            key=_keyCache.get(clazz);
            if(key!=null){
                cachedService=_serviceCache.get(key);
            }
        }finally{
            Job.getJobManager().endRule(readLock);
        }
        if(cachedService!=null){
            @SuppressWarnings("unchecked")
            Type castedService=(Type)cachedService;
            return castedService;
        }
        ServiceReference<Type> ref=_context.getServiceReference(clazz);
        Long sid=(Long)ref.getProperty(Constants.SERVICE_ID);
        Type newService=_context.getService(ref);
        try{
            Job.getJobManager().beginRule(_writeLock, null);
            key=_keyCache.get(clazz);
            if(key!=null){
                cachedService=_serviceCache.get(key);
            }else{
                _keyCache.put(clazz.getName(),sid);
                _serviceCache.put(sid, newService);
            }
        }finally{
            Job.getJobManager().endRule(_writeLock);
        }
        if(cachedService!=null){
            _context.ungetService(ref);
            @SuppressWarnings("unchecked")
            Type castedService=(Type)cachedService;
            return castedService;
        }else{
            _context.addServiceListener(_tracker);
            return newService;
        }
    }

    public Object[] getServices(String clazz,String filter) throws InvalidSyntaxException{
        ServiceReference<?>[] refs=_context.getServiceReferences(clazz,filter);
        if(refs==null){
            return null;
        }
        Object[] services=new Object[refs.length];
        int count=refs.length;
        boolean[] serviceAbsence=new boolean[refs.length];
        Long[] SIDs=new Long[refs.length];
        for(int i=0;i<=count-1;i++){
            ServiceReference<?> ref=refs[i];
            SIDs[i]=(Long)ref.getProperty(Constants.SERVICE_ID);
        }
        boolean loop=true;
        SharedSchedulingRule readLock=new SharedSchedulingRule(_writeLock);
        while(loop){
            try{
                Job.getJobManager().beginRule(readLock, null);
                for(int i=0;i<=count-1;i++){
                    if(_serviceCache.containsKey(SIDs[i])==false){
                        serviceAbsence[i]=true;
                    }
                }
            }finally{
                Job.getJobManager().endRule(readLock);
            }
            for(int i=0;i<=count-1;i++){
                if(serviceAbsence[i]==true){
                    services[i]=_context.getService(refs[i]);
                }
            }
            try{
                Job.getJobManager().beginRule(_writeLock, null);
                boolean gotNewRequire=false;
                for(int i=0;i<=count-1;i++){
                    if(_serviceCache.containsKey(SIDs[i])==false && services[i]==null){
                        serviceAbsence[i]=true;
                        gotNewRequire=true;
                    }
                }
                if(gotNewRequire==false){
                    for(int i=0;i<=count-1;i++){
                        Object service=services[i];
                        if(service!=null){
                            _serviceCache.put(SIDs[i], service);
                        }else{
                            services[i]=_serviceCache.get(SIDs[i]);
                        }
                    }
                    loop=false;
                }
            }finally{
                Job.getJobManager().endRule(_writeLock);
            }
        }
        _context.addServiceListener(_tracker);
        return services;    
    }
    public <Type> Collection<Type> getServices(Class<Type> clazz,String filter) throws InvalidSyntaxException{
        Collection<ServiceReference<Type>> refsCollection=_context.getServiceReferences(clazz,filter);
        HashMap<Integer,Type> services=new HashMap<Integer,Type>(refsCollection.size()+1,1.0f);
        if(refsCollection.size()==0){
            return services.values();
        }
        ArrayList<ServiceReference<Type>> refs=new ArrayList<ServiceReference<Type>>(refsCollection);
        int count=refs.size();
        boolean[] serviceAbsence=new boolean[refs.size()];
        Long[] SIDs=new Long[refs.size()];
        for(int i=0;i<=count-1;i++){
            ServiceReference<Type> ref=refs.get(i);
            SIDs[i]=(Long)ref.getProperty(Constants.SERVICE_ID);
        }
        boolean loop=true;
        SharedSchedulingRule readLock=new SharedSchedulingRule(_writeLock);
        while(loop){
            try{
                Job.getJobManager().beginRule(readLock, null);
                for(int i=0;i<=count-1;i++){
                    if(_serviceCache.containsKey(SIDs[i])==false){
                        serviceAbsence[i]=true;
                    }
                }
            }finally{
                Job.getJobManager().endRule(readLock);
            }
            for(int i=0;i<=count-1;i++){
                if(serviceAbsence[i]==true){
                    services.put(i, _context.getService(refs.get(i)));
                }
            }
            try{
                Job.getJobManager().beginRule(_writeLock, null);
                boolean gotNewRequire=false;
                for(int i=0;i<=count-1;i++){
                    if(_serviceCache.containsKey(SIDs[i])==false && services.containsKey(i)==false){
                        serviceAbsence[i]=true;
                        gotNewRequire=true;
                    }
                }
                if(gotNewRequire==false){
                    for(int i=0;i<=count-1;i++){
                        Object service=services.get(i);
                        if(service!=null){
                            _serviceCache.put(SIDs[i], service);
                        }else{
                            @SuppressWarnings("unchecked")
                            Type cachedService=(Type)_serviceCache.get(SIDs[i]);
                            services.put(i,cachedService);
                        }
                    }
                    loop=false;
                }
            }finally{
                Job.getJobManager().endRule(_writeLock);
            }
        }
        _context.addServiceListener(_tracker);
        return services.values();   
    }

}

This is MultiResourceSchedulingRule.

package lazycatTools.runtime;

import java.util.Collections;
import java.util.Set;
import java.util.HashSet;

import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.jobs.ISchedulingRule;

public class MultiResourceSchedulingRule<ParentType,ResourceType> extends ResourceBindingSchedulingRule<ParentType> implements IMultiResourceSchedulingRule<ParentType,ResourceType>  {

    private final Set<ResourceType> _resources;

    public MultiResourceSchedulingRule(ParentType parent){
        this(parent,new HashSet<ResourceType>());
    }
    public MultiResourceSchedulingRule(ParentType parent,Set<ResourceType> resources){
        super(parent);
        Assert.isLegal(resources!=null);
        _resources=resources;
    }
    @Override
    public boolean isConflicting(ISchedulingRule rule){
        if(rule==this){
            return true;
        }
        if(rule instanceof IResourceBindingSchedulingRule<?>){
            final IResourceBindingSchedulingRule<?> casted=(IResourceBindingSchedulingRule<?>)rule;
            if(_resources.contains(casted.getResource())){
                return true;
            }
        }
        if(rule instanceof IMultiResourceSchedulingRule<?,?>){
            final IMultiResourceSchedulingRule<?,?> casted=(IMultiResourceSchedulingRule<?,?>)rule;
            if(Collections.disjoint(_resources,casted.getResources())==false){
                return true;
            }
        }
        return false;
    }
    @Override
    public boolean contains(ISchedulingRule rule){
        if(rule==this){
            return true;
        }
        if(rule instanceof IResourceBindingSchedulingRule<?>){
            final IResourceBindingSchedulingRule<?> casted=(IResourceBindingSchedulingRule<?>)rule;
            if(_resources.contains(casted.getResource())){
                return true;
            }
        }
        if(rule instanceof IMultiResourceSchedulingRule){
            final IMultiResourceSchedulingRule<?,?> casted=(IMultiResourceSchedulingRule<?,?>)rule;
            if(_resources.containsAll(casted.getResources())){
                return true;
            }
        }
        return false;
    }
    @Override
    public Set<ResourceType> getResources() {
        return Collections.<ResourceType>unmodifiableSet(_resources);
    }   
}

And ResourceBindingSchedulingRule.

package lazycatTools.runtime;

import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.jobs.ISchedulingRule;

public class ResourceBindingSchedulingRule<ResourceType> implements IResourceBindingSchedulingRule<ResourceType> {

    private final ResourceType _resource;

    public ResourceBindingSchedulingRule(ResourceType resource){
        Assert.isLegal(resource!=null);
        _resource=resource;
    }

    /* (non-Javadoc)
     * @see lazycatTools.runtime.IResourceBindingSchedulingRule#getResource()
     */
    @Override
    public ResourceType getResource() {
        return _resource;
    }

    @Override
    public boolean contains(ISchedulingRule rule) {
        return isConflicting(rule);
    }

    @Override
    public boolean isConflicting(ISchedulingRule rule) {
        if(rule==this){
            return true;
        }
        if(rule instanceof IResourceBindingSchedulingRule<?>){
            final IResourceBindingSchedulingRule<?> casted=(IResourceBindingSchedulingRule<?>)rule;
            return _resource==casted.getResource();
        }
        return false;
    }


}

SharedSchedulingRule which is used as the readLock in the example.

package lazycatTools.runtime;

import org.eclipse.core.runtime.jobs.ISchedulingRule;

public class SharedSchedulingRule implements ISchedulingRule {

    private final ISchedulingRule _rule;

    public SharedSchedulingRule(ISchedulingRule rule){
        _rule=rule;
    }

    @Override
    public boolean contains(ISchedulingRule rule) {
        if(rule==this){
            return true;
        }
        return _rule.contains(rule);
    }

    @Override
    public boolean isConflicting(ISchedulingRule rule) {
        if(rule==this){
            return true;
        }
        return _rule.isConflicting(rule);
    }

}
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-10T21:10:58+00:00Added an answer on June 10, 2026 at 9:10 pm

    The best option is to make everything immutable. Then you don’t need to worry about anything 🙂

    Assuming this isn’t possible, then I would recommend not making your library thread-safe.

    • Thread safety will usually add overhead. In a low level library, you shouldn’t force users to pay a performance penalty for safety that they might not need.
    • Even if you add thread safety at the level of your library, users will still probably have to add their own locking at a higher level (this is because locks don’t compose). So you probably aren’t actually saving your users any work.
    • You can always add a synchronised wrapper later if needed. But you can’t remove synchronisation if it is baked in.
    • It will make your own library code simpler. You can focus on better features rather than worrying about locks.

    There are good examples in the Java standard library that follow this approach and logic – e.g. ArrayList is not thread safe.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

link Im having trouble converting the html entites into html characters, (&# 8217;) i
I have a string like this: La Torre Eiffel paragonata all&#8217;Everest What PHP function
I am doing a simple coin flipping experiment for class that involves flipping a
I'm parsing an RSS feed that has an &#8217; in it. SimpleXML turns this
I have thousands of HTML files to process using Groovy/Java and I need to
I have a .ini file as follows: [playlist] numberofentries=2 File1=http://87.230.82.17:80 Title1=(#1 - 365/1400) Example
That's pretty much it. I'm using Nokogiri to scrape a web page what has
I have just tried to save a simple *.rtf file with some websites and
I want to count how many characters a certain string has in PHP, but
I would like to count the length of a string with PHP. The string

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.