Java synchronization: Synchronization method and synchronization block - java

I have a mulitThread Java application. In one method, there is a need to synchronize a ArrayList. Since arrayList is not a thread safe, so I have to use synchonization. The problem is that object which is type of ArrayList is not a member variable of the object. Prototype of the method is as follows:
public void simultaneousAccess(ArrayListWrapper aListWrapper){
ArrayList list = aListWrapper.getList();
//...Codes manipulate the list
}
Due to mulitthreading, shall I use
A)
public void synchronized simultaneousAccess(ArrayListWrapper aListWrapper){
ArrayList list = aListWrapper.getList();
//...Codes manipulate the list
}
Or
B)
public void simultaneousAccess(ArrayListWrapper aListWrapper){
ArrayList list = aListWrapper.getList();
Synchronized(list){
//...Codes manipulate the list
}
}
From the performance test, neither works.
But I donot know why?
Here comes whole source codes:
package com.juhani.prototype.sync;
import java.util.ArrayList;
public class ArrayListWrapper {
public ArrayList<Integer> aList = new ArrayList<Integer>();
public ArrayListWrapper(){
Integer one = new Integer(1);
Integer two = new Integer(2);
Integer three = new Integer(3);
aList.add(one);
aList.add(two);
aList.add(three);
}
}
package com.juhani.prototype.sync;
import java.util.ArrayList;
public class TestClass {
public int count_test=0;
public synchronized void test(ArrayListWrapper listWrapper){
ArrayList<Integer> list = listWrapper.aList;
int temp = list.get(1)+1;
list.set(1,temp);
}
public void testBlock(ArrayListWrapper listWrapper){
ArrayList<Integer> list = listWrapper.aList;
synchronized(list){
int temp = list.get(1)+1;
list.set(1,temp);
}
}
}
package com.juhani.prototype.sync;
public class WorkerSyncObj extends Thread {
ArrayListWrapper listWrapper = null;
TestClass tc = null;
int number;
public WorkerSyncObj(int aNumber){
number = aNumber;
}
public void setListWrapper(ArrayListWrapper aListWrapper){
listWrapper = aListWrapper;
}
public void setTestClass(TestClass aTc){
tc = aTc;
}
public void run(){
int i = 1000;
for(int j=0;j<i;j++){
tc.testBlock(listWrapper);
System.out.println("Thread "+number+" is runing at loop "+j+" . index 1 value is:"+listWrapper.aList.get(1));
}
}
}
package com.juhani.prototype.sync.main;
import com.juhani.prototype.sync.ArrayListWrapper;
import com.juhani.prototype.sync.TestClass;
import com.juhani.prototype.sync.WorkerSyncObj;
public class TestMain {
public static void main(String[] args){
ArrayListWrapper list = new ArrayListWrapper();
TestClass tc = new TestClass();
WorkerSyncObj work1 = new WorkerSyncObj(1);
work1.setListWrapper(list);
work1.setTestClass(tc);
WorkerSyncObj work2 = new WorkerSyncObj(2);
work2.setListWrapper(list);
work2.setTestClass(tc);
WorkerSyncObj work3 = new WorkerSyncObj(3);
work3.setListWrapper(list);
work3.setTestClass(tc);
work1.start();
work2.start();
work3.start();
}
}

In the first case you lock on the this object while in the second on the list object. This might be a problem if you call the method from different objects but the list is the same. This is can be the reason of the exception in the first case.
Alternatively you could try some built-in concurrent types like Collections.synchronizedList or CopyOnWriteArrayList.

In java, every object instance has an intrinsic lock (as well as corresponding class itself). Synchronzied keywork is actually use the intrinsic lock for exclusive access, i.e.
syncrhonized method(...) {...}
is equal to
method(...) {
this.intrinsicLock.lock();
...;
this.intrinsicLock.unlock() }
And
synchronized( obj_ref ) { ... }
is equal to
obj_ref.intrinsicLock.lock();
{...}
obj_ref.instrinsicLock.unlock();
So, syncrhonized the method is not right for the protection of list (the parameter). There are two problems if you use the synchronized( list):
1. The granularity of exclusive access seems a little gross
2. Every list access wherever in the whole program need to use "synchronized( list )" too. This is a protocol (for the exclusive acess).
That's the reason why Java library provide quite some concurrent data structures.

Related

Possibility of Race Condition on using Java Locks

I've written a Java class and someone has reviewed the code and insisted that there could be a race condition in method calculate. Here's a simplified version of the class code:
public class MyClass {
private List<Integer> list;
private final ReadWriteLock lock;
public MyClass() {
list = new ArrayList<>();
lock = new ReentrantReadWriteLock();
}
public void add(Integer integer) {
lock.writeLock().lock();
try {
list.add(integer);
} finally {
lock.writeLock().unlock();
}
}
public void deleteAll() {
lock.writeLock().lock();
try {
list.clear();
} finally {
lock.writeLock().unlock();
}
}
public Integer calculate() {
List<Integer> newList = new ArrayList<>();
Integer result = 0;
lock.readLock().lock();
try {
list.forEach(integer -> {
// calculation logic that reads values from 'list' and adds only a subset of elements from 'list' in 'newList'
});
} finally {
lock.readLock().unlock();
}
setList(newList);
return result;
}
private void setList(List<Integer> newList) {
lock.writeLock().lock();
try {
list = newList;
} finally {
lock.writeLock().unlock();
}
}
}
Now my question is:
Can a race condition really happen in this method, and if so how can I solve it (either using locks or using any other method to make the class thread safe)?
Any advice would be appreciated.
There is a time gap between creation of newList and call to setList(newList). We may assume this time gap is arbitrary long, and everything can happen when it lasts, e.g. another thread adds an object which must be retained, but it will be lost when call to setList(newList) removes list with that new object.
In fact, the method calculate is modifying and should do all the work under write lock.
To clarify the above ... the statement
List<Integer> newList = new ArrayList<>();
... instantiates a data-structure (list ...) that will subsequently be used within the block of code that is intended to be protected by lock.readLock().lock();, but is not contained within it. Therefore it is not protected.
To remedy the problem, the declaration of newList should not include initialization. Nothing which affects the presumed value of this variable should exist outside of the lock-protected block.

Why the result which the system should print to me changes every time(java concurrency)?

I have a problem in concurrency programming in java. Please look at the code below. The result which system should print to me, changes every time I run the program. Although I’ve synchronized the operation of adding value to sub variable, but the result changes every time. I think I’ve made a mistake somewhere. But I do not know where.
public class Test {
public static void main(String[] args) {
final MyClass mClass = new MyClass();
int size = 10;
final CountDownLatch cdl = new CountDownLatch(size);
for(int i = 0; i < size; i++){
Thread t = new Thread(new Runnable() {
#Override
public void run() {
for(int number = 0; number < 100000; number++){
mClass.addToSub(number);
}
cdl.countDown();
}
});
t.start();
}
try {
cdl.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
//the result changes every time!!!!!!!!
System.out.println(mClass.getSub());
}
public static class MyClass {
private Long sub = 0L;
public long getSub() {
synchronized (sub) {
return sub;
}
}
public void addToSub(long value){
synchronized (sub) {
sub += value;
}
}
}
}
What you are getting wrong here is not the multi-threading. What is causing this issue is a java feature called auto-boxing.
Your variable sub has the type Long which is a reference to an object (Long and long are different).
You need to have an object to synchronize on in java so you can not use just a normal long.
The problem here is that a Long is immutable meaning the value does not change. So when you do sub += value you are actually doing sub = Long.valueOf(sub.longValue() + value) witch is creating a new object.
So the current thread only has the previous object locked so new threads can still change the reference sub.
What you want to do is synchronize on a reference that wont change, i.e this
public void addToSub(long value){
synchronized (this) {
sub += value;
}
}
Or more terse:
public synchronized void addToSub(long value) {
sub += value;
}
And you should probably use long and not Long.
EDIT
As noted in Thomas Timbuls answer you probably want to use AtomicLong as that gives you thread-safety by default and potentially much better performance (as the threads don't need to wait for each-other).
In addToSub you are changing the value on which you synchronize. Effectively this means that there is no synchronization at all.
Either sync on this, or even better, use AtomicLong and avoid both your problem as well as synchronization overhead (Thread contention):
public static class MyClass {
private AtomicLong sub = new AtomicLong();
public long getSub() {
return sub.get();
}
public void addToSub(long value){
sub.addAndGet(value);
}
}
The Atomic* classes are specifically designed for this type of usecase, where a single variable is updated by multiple Threads, and where synchronize could result in heavy thread contention. If you are dealing with Collections, look towards the ones in java.util.concurrent.*
Edit:
Thanks for the correction of addAndGet vs incrementAndGet.
You're synchronizing on a non-final value:
synchronized (sub) {
This means that as soon as you change it to some other value:
sub += value;
anything which isn't already waiting at the synchronized block can proceed, because nothing is holding the monitor for this new value.
Synchronize on this instead (or some other unchanging value):
synchronized (this) {
sub is an object (Long), change to long and add a private Object for the synchronized. Then it will work.
public static class MyClass {
private Object locker = new Object();
private long sub = 0L;
public long getSub() {
synchronized (locker) {
return sub;
}
}
public void addToSub(long value){
synchronized (locker) {
sub += value;
}
}
}

Allow only one thread at the time to use an object

I have the following class:
public class MyClass{
private List<Integer> ints = new LinkedList<Integer>();
public List<Integer> getInts(){
return ints;
}
public synchronized void doAction(){
//Do some with the list
}
}
I need to allow only one thread at the time having acces to the List. I would do that as follows:
public class MyClass{
private List<Integer> ints = new LinkedList<Integer>();
private static final Semaphore s = new Semaphore(1);
public List<Integer> getInts(){
s.acquire();
return ints;
}
public void release(){
s.release();
}
public synchronized void doAction(){
s.acquire();
//Do some with the list
s.release();
}
}
But the implementaion is obviously not reliable, because if the client request the List through the getter for adding some elements into it and forget to call release() we'll get into troubles if try to invoke the doAction method.
What is the solution for the problem?
Don't allow the client to get the reference. Put all the methods that work on the list to MyClass and synchronize them.
You can allow the users to get a snapshot copy of the list however.
You could use a synchronized list:
private List<Integer> ints = Collections.synchronizedList(new LinkedList<Integer>());

Java - ArrayList in another method is empty

I'm adding packets to ArrayList in PacketList Class from another classes.
public class PacketList {
public ArrayList<PcapPacket> packets;
public PacketList(){
packets = new ArrayList<PcapPacket>();
}
public void addPacket(PcapPacket packet){
packets.add(packet);
System.out.printf("List size: %d\n", packets.size()); // Size is according to added objects into the list.
}
Until now everything is working fine, but when I create another method to retrieve the list, it's empty..
public ArrayList getList(){
System.out.printf("Size of list in PacketList: %d\n", packets.size()); // Size is 0
return packets;
}
Edit: Sorry, it's actually whole code, only chopped..
import java.util.ArrayList;
import org.jnetpcap.packet.PcapPacket;
public class PacketList {
public ArrayList<PcapPacket> packets;
public PacketList(){
packets = new ArrayList<PcapPacket>();
}
public void addPacket(PcapPacket packet){
System.out.printf("Received packet .. caplen=%-4d\n", packet.getCaptureHeader().caplen());
packets.add(packet);
System.out.printf("List size: %d\n", packets.size()); // Size is according to added objects into the list.
}
public ArrayList getList(){
System.out.printf("Size of list in PacketList: %d\n", packets.size()); // Size is 0
return packets;
}
}
Here I create PacketList
public class ThreadToSwitch implements Runnable {
PacketList pl = new PacketList();
public void run(){
// here I have just pcap init that i did not include, but the packet is ok
PcapPacketHandler<String> jpacketHandler = new PcapPacketHandler<String>() {
public void nextPacket(PcapPacket packet, String user) {
if(packet != null)
pl.addPacket(packet);
}
};
}
This is main where I call getList():
public class SwrMain extends Thread{
public static void main(String[] args) {
Thread tts = new Thread(new ThreadToSwitch());
Thread ttr = new Thread(new ThreadToRouter());
tts.start();
ttr.start();
ArrayList pList;
int myint = -1;
while(myint != 0){
Scanner keyboard = new Scanner(System.in);
myint = keyboard.nextInt();
if(myint == 1){
System.out.printf("\nNumber of packets in list: %d\n", (new PacketList().getList().size()));
}
}
}
}
This is just a guess, but you are probably calling PacketList.getList() from another thread than the one where you add packets. You might be running into some synchronization issue. If that's the case, try switching to a concurrent structure, probably a ConcurrentLinkedQueue.
Seeing your full code (including the code where you read the list) would help diagnose the problem.
So your issue is that you are creating a new packetlist, then asking its size. It is not the same packetlist that you create in the ThreadToSwitch method, but its own instance, created by the default constructor for PacketList when you call new PacketList
public class SwrMain extends Thread{
public static void main(String[] args) {
Thread tts = new Thread(new ThreadToSwitch());
Thread ttr = new Thread(new ThreadToRouter());
tts.start();
ttr.start();
ArrayList pList;
int myint = -1;
while(myint != 0){
Scanner keyboard = new Scanner(System.in);
myint = keyboard.nextInt();
if(myint == 1){
System.out.printf("\nNumber of packets in list: %d\n", (new PacketList().getList().size()));
}
}
}
}
Think of it like this. I have a dog named Fido. I feed Fido until he is a really fat dog. You also have a dog named Fido. No matter how much I feed my Fido, your Fido doesn't get fat. They are different, even though they are named the same thing.
Now, if I were to borrow your Fido for a while and feed him a lot, then your Fido would be fat.

Hashtable interface, used for setting a key a instance of an object

My add to hashtable method fails, what have i done wrong? Or what have i missunderstood?
test:
#Test
public void testAddKeyValue() {
AdminController cont = new AdminController();
Apartment o1 = new Apartment(1, 4, "Maier B", true);
ArrayList<Expense> exp = new ArrayList<>();
cont.addKeyWithList(o1, exp);
assertTrue(cont.isEmpty()); // ISSUE > the test works if it is true, but it is supposed be False.
}
repo class:
public class Repository extends HashMap<Apartment, ArrayList<Expense>>{
private Map<Apartment,ArrayList<Expense>> dic; // last expense object refers to curret month
Iterator<Map.Entry<Apartment, ArrayList<Expense>>> it;
public void addKeyWithList(Apartment apt, ArrayList<Expense> exp){
dic.put(apt, exp);
}
}
Why is my test not working? Or where in the code have I done something wrong?
Don't extend HashMap as you're doing. Use a HashMap and delegate to it:
public class Repository {
private Map<Apartment, List<Expense>> dic = new HashMap<Apartment, List<Expense>>();
public void addKeyWithList(Apartment apt, ArrayList<Expense> exp){
dic.put(apt, exp);
}
public boolean isEmpty() {
return dic.isEmpty();
}
}
At the moment, Repository is a HashMap, but you don't store anything in it: you store the values in another HashMap contained in Repository.
Also, storing an iterator in a field is a bad idea. iterators can be used only once. Once they have iterated, the can't iterate anymore. It should be a local variable.

Categories

Resources