私は本当に苦痛な Java 学習曲線を経験しましたが、まだ初心者です。
低レベルのライブラリ クラスを設計しています。将来的には、マルチスレッド環境またはシングル スレッドで使用できるようになる可能性があります。私にはそれがわかりません。
このクラスのユーザーに外部からの同期を許可できます。しかし、それはスレッド セーフ バージョンを提供するよりもはるかに非効率的です。
これがpコードです。
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;
}
}
リードロックがブロックされないため、外部から同期するよりもはるかに高速になります。すべてのメソッド呼び出しで作成され、ガベージ コレクションされます。
問題:
オーバーヘッド。WriteLock は非常に複雑で、ReadLock は安価で単純ですが、すべてのメソッド呼び出し (および場合によっては複数回) で作成されるため、依然としてオーバーヘッドが生じます。
そのようなすべてのクラスのスレッド セーフ バージョンを提供する必要がありますか? すべてのオープンソース ライブラリがそうしているわけではありません。しかし、私がそれを提供しない場合、ユーザーが外部から同期できるようにすると、パフォーマンスが低下します。
それとももっと良い方法がありますか?
編集:
分けるべきですか?
ステートレス プロセッサとストアに分割し、ユーザーが readLock/writeLock を作成してロックできるようにしますか? そうすれば、ストアは完全にプロセッサ用に設計され、他のクラスにはあまり意味がなくなり、ライブラリはそれらによって急速にブームになります。
これが私の実際のコードです。嫌なら無視していい。
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();
}
}
これが 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);
}
}
そして 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;
}
}
例で readLock として使用されている SharedSchedulingRule。
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);
}
}