Reputation: 8988
I am facing this issue, I have two classes A and B , 'class A' has two Threads t1 and t2 and its trying to access 'Class B' map as below now the problem is, I can not make any changes on class B' map hence I can not use synchronised
keyword or I can not put it in synchronised method. So my doubt is, is there any other way to synchronise this map.
public class A{
static B b = new B();
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
Map<Integer,String> map = Collections.synchronizedMap(b.getMap());
map.put(1, "one");
map.put(2, "two");
map.put(3, "three");
b.setMap(map);
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
Map<Integer,String> map = Collections.synchronizedMap(b.getMap());
map.put(4, "four");
map.put(5, "five");
map.put(6, "six");
b.setMap(map);
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for(Map.Entry<Integer, String> entry : b.getMap().entrySet()){
System.out.println(entry.getKey() + ":" + entry.getValue());
}
}
I am using LinkedHashMap
, only to track the order of insertion (ignore performance issues)
public class B{
private Map<Integer,String> map = new LinkedHashMap<Integer,String>();
public Map<Integer,String> getMap() {
return map;
}
public void setMap(Map<Integer,String> map) {
this.map = map;
}
}
Upvotes: 0
Views: 251
Reputation: 180161
As others indicated, you can use a synchronized wrapper, and java.util.Collections
provides a convenient means to obtain one. Having each thread get its own synchronized wrapper does not help you, though -- all participants need to use the same synchronization tool.
More generally, if you need to synchronize access to some less convenient object then you can use external synchronization. In your case, that might look like this:
public class A{
static B b = new B();
// will use this object to synchronize access to b's map:
static Object bLock = new Object();
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
Map<Integer,String> map = b.getMap();
synchronized(bLock) {
map.put(1, "one");
map.put(2, "two");
map.put(3, "three");
}
// no need for setMap()
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
Map<Integer,String> map = b.getMap();
synchronized (bLock) {
map.put(4, "four");
map.put(5, "five");
map.put(6, "six");
}
// no need for setMap()
}
});
// ...
}
}
Package java.util.concurrent.locks has some lock classes that you can use, too, but often you don't need anything so fancy.
Upvotes: 1
Reputation: 13222
Why not just set the map in B. If you cant use ConcurrentHashMap
then you can use the Collections.synchronizedMap(new LinkedHashMap<>())
instead. Any external synchronization will always leave the possibility of unsynchronized access to the map.
public class A{
static B b;
static {
b = new B();
b.setMap(new ConcurrentHashMap());
}
//...
}
Upvotes: 1
Reputation: 517
You can create the synchronized Map
once and have both threads use that one Map
instance.
final Map<Integer,String> map = Collections.synchronizedMap(b.getMap());
b.setMap(map);
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
map.put(1, "one");
map.put(2, "two");
map.put(3, "three");
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
map.put(4, "four");
map.put(5, "five");
map.put(6, "six");
}
});
Upvotes: 2
Reputation: 810
Simply:
public class A{
static B b;
static Map bMap;
static {
b = new B();
bMap = Collections.synchronizedMap(b.getMap());
}
... //now use bMap instead
}
Upvotes: 0