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>());
Related
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.
I want to detect when adding some items to the array list or when removing some item from it. Actually I have some code like below:
public class myClass {
MyCustomArrayList<MyObject> al;
public void method1() {
al.add(myObject);
// Do other works
al.remove(myObject)
// Do other works
}
private void DoByEachAdd() {
//I want array list call this method by adding each item to it.
// It should be in this class because it is doing some works
// related to this class. for example changing some private variables
}
private void DoByEachRemove() {
// I want array list call this method by adding each item to it.
// It should be in this class too.
}
}
I know that array list has not the ability for having listener or some kind of notifications or events and if I want to detect add should have a custom array list. something like below class:
class MyArrayList<T> {
private ArrayList<T> list;
public MyList(){
list = new ArrayList<>();
...
}
public void add(T t) {
list.add(t) {
//do other things you want to do when items are added
}
public T remove(T t) {
list.remove(t);
//do other things you want to do when items are removed
}
(I get it from here)
So the question is that: how can I inform the object of MyArrayList (al) that call DoByEachAdd and DoByEachRemove methods when the remove and add method fired. Does some body have any ideas?
First, follow naming convention. Second, the three class names you used for the same class, MyList, MyArrayList and MyCustomArrayList will confuse people. As for your question, you would have to have an instance field inside MyArrayList of type myClass (unless you want to refactor DoByEachAdd and DoByEachRemove to be static). This can be done by adding it as a constructor parameter, e.g.
// inside MyArrayList
private ArrayList<T> list;
private final myClass instance;
public MyArrayList(myClass instance) { // <-- NOT MyList
list = new ArrayList();
this.myClass = myClass;
}
Also, I question your approach. Other classes with instances of MyArrayList can only use the add and remove methods of ArrayList. If you want to save a lot of bother and have all methods visible, either declare list as public final or make MyArrayList a subclass of ArrayList, e.g.
public class MyArrayList<T> extends ArrayList<T> {
private final myClass instance;
public MyArrayList(myClass instance) { // <-- NOT MyList
list = new ArrayList();
this.myClass = myClass;
}
#Override
public boolean add(T t) {
boolean returnThis = super.add(t);
// do some stuff
instance.DoByEachAdd();
return returnThis;
}
#Override
public boolean remove(T t) {
boolean returnThis = super.remove(t);
// do some stuff
instance.DoByEachRemove();
return returnThis;
}
}
If you insist on being able to return a T from remove, declare another method:
public T removeT(T t) {
remove(t);
// do some stuff
return someT;
}
you need to give access to your myClass to MyArrayList
class MyArrayList<T> {
private ArrayList<T> list;
private myClass theClass;
public MyList(myClass theClass){
list = new ArrayList<>();
this.theClass = theClass;
...
}
public void add(T t) {
list.add(t) {
//do other things you want to do when items are added
theClass.DoByEachAdd();
}
public T remove(T t) {
list.remove(t);
//do other things you want to do when items are removed
theClass.DoByEachRemove
}
and in your myClass give the object to your list
public class myClass {
MyCustomArrayList<MyObject> al;
public myClass(){
al = new MyCustomArrayList<MyObject>(this);
}
public void method1() {
al.add(myObject);
// Do other works
al.remove(myObject)
// Do other works
}
public void DoByEachAdd() {
//I want array list call this method by adding each item to it.
// It should be in this class because it is doing some works
// related to this class. for example changing some private variables
}
public void DoByEachRemove() {
// I want array list call this method by adding each item to it.
// It should be in this class too.
}
}
I have an ArrayList in Java. Now, I want to access the pointer to the said list. This is so that I can make a variable out of the pointer and make operations using it. Any advise on how to do this?
What I want to do exactly is similar to making "list" below always point to the value of "someOtherList".
import java.util.ArrayList;
import java.util.List;
public class ListContainingObject {
private List list;
public List getList() {
return list;
}
public void setList(List list) {
this.list = list;
}
public static void main(String args[]){
ListContainingObject listContainingObject= new ListContainingObject();
System.out.println(listContainingObject.getList());
List someOtherList = new ArrayList();
listContainingObject.setList(someOtherList);
System.out.println(listContainingObject.getList());
System.out.println(someOtherList);
someOtherList.add("1");
System.out.println(listContainingObject.getList());
System.out.println(someOtherList);
//I want the two below to have the same value
someOtherList = new ArrayList();
System.out.println(listContainingObject.getList());
System.out.println(someOtherList);
}
}
The seemingly appropriate workaround would be to call the setters again explicitly like below.
public class ListContainingObject {
public void resetList(List toReset) {
this.list = new ArrayList();
toReset = this.list;
}
}
listContainingObject.resetList(someOtherList);
But this would lead to another problem wherein I want solcowiab.getList() and listContainingObject.getList() below to always be the same, assuming that I don't have the source code for SomeOtherListContainingObjectWhichIsABlackBox.
import java.util.ArrayList;
import java.util.List;
public class ListContainingObject {
private List list;
public List getList() {
return list;
}
public void setList(List list) {
this.list = list;
}
public static void main(String args[]) {
ListContainingObject listContainingObject = new ListContainingObject();
SomeOtherListContainingObjectWhichIsABlackBox solcowiab = new SomeOtherListContainingObjectWhichIsABlackBox();
List aNewList = new ArrayList();
aNewList.add("1");
solcowiab.setList(aNewList);
listContainingObject.setList(solcowiab.getList());
System.out.println(listContainingObject.getList());
System.out.println(solcowiab.getList());
//The two below will have the same value but
//at some point "list" did not point to "someOtherList"
solcowiab.aMethodThatSupposedlyWontCallSetList();
listContainingObject.setList(solcowiab.getList());
System.out.println(listContainingObject.getList());
System.out.println(solcowiab.getList());
}
}
class SomeOtherListContainingObjectWhichIsABlackBox {
private List someOtherList;
public List getList() {
return someOtherList;
}
public void setList(List list) {
this.someOtherList = list;
}
public void aMethodThatSupposedlyWontCallSetList() {
//this one won't be observed by ListContainingObject
setList(new ArrayList());
getList().add("2");
//do some other stuff
//only this assignment will be controlled by ListContainingObject's main method
setList(new ArrayList());
}
}
You can't because the line someOtherList = new ArrayList(); is assigning a whole new "section of memory" to someOtherList, meaning it will point to a different place in memory than listContainingObject.getList().
Now it is true that the listContainingObject has only a reference to your created list, but this reference is not semantically linked to someOtherList. So if someOtherList changes, your object won't know about it.
If you want to clear the lists without destroying the link, use someOtherList.clear() instead.
EDIT: You may be able to get away with resetting the list another way:
public class ListContainingObject {
public void resetList(List toReset) {
this.list = new ArrayList();
toReset = this.list;
}
}
listContainingObject.resetList(someOtherList);
This is, however, a pretty dirty hack. But without somehow manually changing both variables to reference the new structure in memory, I know of no way to get one to automatically update the other.
Probably, you are trying to update the contents of the "list" field.
Please find an solution here:
import java.util.ArrayList;
import java.util.List;
public class ListContainingObject {
private List list;
public List getList() {
return list;
}
public void setList(List list) {
this.list = list;
}
public static void main(String args[]){
ListContainingObject listContainingObject= new ListContainingObject();
System.out.println(listContainingObject.getList());
List someOtherList = new ArrayList();
listContainingObject.setList(someOtherList);
System.out.println(listContainingObject.getList());
System.out.println(someOtherList);
someOtherList = listContainingObject.getList();
someOtherList.add("1");
System.out.println(listContainingObject.getList());
System.out.println(someOtherList);
//I want the two below to have the same value
//someOtherList = new ArrayList();
someOtherList.clear();
System.out.println(listContainingObject.getList());
System.out.println(someOtherList);
}
}
Thus, someOtherList is referring to the "list" field which is the same.
You have to again setList to the new address as once someOtherList is referring to different. So, as required "list" should be updated also and must be followed elsewhere.
Suppose you have a method, which modifies this list you can achieve this by below.
public void someMethod(){
List someOtherList = getList();
someOtherList = new ArrayList();
//some code
setList(someOtherList);
}
For similar post check: Confused, whether java uses call by value or call by reference when an object reference is passed?
first the someotherlist is pointing to an object in heap
someotherlist ----> Object
then you are making two references to point to the same object in the heap
someotherlist ----
|
Object
|
list -------------
now when you assign the reference someotherlist to a new object in the heap
someotherlist ------> new Object
the object refered by list will not be changed
list -----------> oldobject
you have to call the setters again to make list point to the new object refered by someotherlist
Object (now eligible for garbage collection as referred by none)
someotherobject ------
|
new Object
|
list ------
Note:
you can only refer objects not object references.. what you can do is set up a method for setting the object to someotherlist and assign the same reference to the list also... like
class Test {
List<E> list;
List<E> someOtherList;
setterMethod(ArrayList<E> a) {
someOtherList = a;
list = someOtherList;
}
Edit:
class One {
List<E> list;
public void setList(List<E> newList) {
this.list = newList;
}
//getters and setters and other methods
}
class Two {
One one;
List<E> someOtherList;
public void setSomeOtherList(List<E> newList) {
this.someOtherList = newList;
this.one.setList(newList);
}
//getters and setters and other methods
}
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.
Basically I have an integer array which i want to hand over to a thread, but i can't get the syntax right.
// Create list
List <Integer> list = new ArrayList<Integer>();
// Create thread
TPServer server = new TPServer(port, <Integer> list);
new Thread(server).start();
// Below is the TPServer class
// TPServer Class
public class TPServer implements Runnable {
private List <Integer> list = null;
private int port = 0;
private boolean isStopped = false;
public TPServer(int port, List <Integer> list) {
this.list = list;
this.port = port;
}
}
You haven't implemented Runnable and also it should be new TPServer(port, list);
You pass a generic argument the same as any other.
TPServer server = new TPServer(port, list);
You might wanna use a list that uses a semaphore to prevent concurent access Or use a list type that is thread safe, if your list is being used also out of the thread. (and if it is used only inside the thread, create it inside obviously :=) )