I've got the following code pieces , containing 2 different methods that both methods will be accessed by many threads (getWeapon() and returnWeapon()).
Please anyone who can answer some or all of the following questions: 1. How can I make it as efficient as possible? 2. Can I not use the synchronized block? 3. Is it better to use a different Object as the key to the synchronizd block? 4. Is it better to use ReentrantLock/ReadWriteLock to handle this cuncurrent multi-threading cases?
private static final int M16_NUM_WEAPONS = 2;
private static final int AK47_NUM_WEAPONS = 5;
private static final int UZI_NUM_WEAPONS = 9;
private Map<Class<? extends Weapon>, Integer> WeaponsToAmountMap;
public Arsenal() {
this.synchronizedWeaponsToAmountMap = new ConcurrentHashMap<Class<? extends Weapon>, Integer>();
}
public void initializeWeapons() {
synchronizedWeaponsToAmountMap.put(M16.class, M16_NUM_WEAPONS);
synchronizedWeaponsToAmountMap.put(AK47.class, AK47_NUM_WEAPONS);
synchronizedWeaponsToAmountMap.put(Uzi.class, UZI_NUM_WEAPONS);
}
public Weapon getWeapon(Fighter fighter) {
List<Class<? extends Weapon>> allowedWeapons = new ArrayList<>(fighter.getAllowedWeapons());
Class<? extends Weapon> weaponClass = null;
for (Class<? extends Weapon> allowedWeapon : allowedWeapons){
synchronized (this) {
Integer amount = synchronizedWeaponsToAmountMap.get(allowedWeapon);
if (amount != null && amount > 0) {
synchronizedWeaponsToAmountMap.put(allowedWeapon, amount - 1);
System.out.println("Taking : "+allowedWeapon.getSimpleName());
weaponClass = allowedWeapon;
break;
}
}
}
if (weaponClass==null){
return null;
}
Weapon weapon = null;
try {
weapon = weaponClass.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return weapon;
}
public void returnWeapon(Weapon weapon) {
if (weapon==null){
return;
}
synchronized(this) {
System.out.println("returning : "+weapon.getClass().getSimpleName());
synchronizedWeaponsToAmountMap.put(weapon.getClass(), synchronizedWeaponsToAmountMap.get(weapon.getClass()) + 1);
}
}