How to prevent deadlocks in synchronized methods? - java

In the following Code there is a potential to enter a Deadlock similar to this Question "Deadlocks and Synchronized methods", now i understand why the two Threads are entering a
deadlock, but when i execute the code the Threads always enters a Deadlock so:
1 - When is a Deadlock not possible in this code ?
2 - How to prevent it from happening ?
I tried using wait() and notifyAll() like this :
wait()
waver.waveBack(this)
and then calling notifyAll() in waveBack(), but it didn't work what am i missing or misunderstood ?
package mainApp;
public class Wave {
static class Friend {
private final String name;
public Friend(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public synchronized void wave(Friend waver) {
String tmpname = waver.getName();
System.out.printf("%s : %s has waved to me!%n", this.name, tmpname);
waver.waveBack(this);
}
public synchronized void waveBack(Friend waver) {
String tmpname = waver.getName();
System.out.printf("%s : %s has waved back to me!%n", this.name, tmpname);
}
}
public static void main(String[] args) {
final Friend friendA = new Friend("FriendA");
final Friend friendB = new Friend("FriendB");
new Thread(new Runnable() {
public void run() {
friendA.wave(friendB);
}
}).start();
new Thread(new Runnable() {
public void run() {
friendB.wave(friendA);
}
}).start();
}
}

In this case, simply do not call another method that might need the lock while holding the lock. This ensures that there is always a moment in time where a method can get the lock and progress can be made.
Calling wait() before waver.waveBack(this) causes a chicken and egg problem: waveBack(this) is never called because the thread stops execution at the wait() statement and thus notifyAll() is never called to continue execution.
There are various ways to prevent deadlocks in the context of the example, but let's go with the advice from sarnold in one of the comments in his answer from the question you linked. To paraphrase sarnold: "it is usually easier to reason about locks on data".
Let's assume that the synchronized methods are synchronized to ensure some consistent update of state (i.e. some variables need to be updated but only one thread at any given time can modify these variables). For example, let's register the amount of waves send and waves received. The runnable code below should demonstrate this:
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class Wave {
static class Waves {
final Map<Friend, Integer> send = new HashMap<>();
final Map<Friend, Integer> received = new HashMap<>();
void addSend(Friend f) {
add(f, send);
}
void addReceived(Friend f) {
add(f, received);
}
void add(Friend f, Map<Friend, Integer> m) {
m.merge(f, 1, (i, j) -> i + j);
}
}
static class Friend {
final String name;
public Friend(String name) {
this.name = name;
}
final Waves waves = new Waves();
void wave(Friend friend) {
if (friend == this) {
return; // can't wave to self.
}
synchronized(waves) {
waves.addSend(friend);
}
friend.waveBack(this); // outside of synchronized block to prevent deadlock
}
void waveBack(Friend friend) {
synchronized(waves) {
waves.addReceived(friend);
}
}
String waves(boolean send) {
synchronized(waves) {
Map<Friend, Integer> m = (send ? waves.send : waves.received);
return m.keySet().stream().map(f -> f.name + " : " + m.get(f))
.sorted().collect(Collectors.toList()).toString();
}
}
#Override
public String toString() {
return name + ": " + waves(true) + " / " + waves(false);
}
}
final static int maxThreads = 4;
final static int maxFriends = 4;
final static int maxWaves = 50_000;
public static void main(String[] args) {
try {
List<Friend> friends = IntStream.range(0, maxFriends)
.mapToObj(i -> new Friend("F_" + i)).collect(Collectors.toList());
ExecutorService executor = Executors.newFixedThreadPool(maxThreads);
Random random = new Random();
List<Future<?>> requests = IntStream.range(0, maxWaves)
.mapToObj(i -> executor.submit(() ->
friends.get(random.nextInt(maxFriends))
.wave(friends.get(random.nextInt(maxFriends)))
)
).collect(Collectors.toList());
requests.stream().forEach(f ->
{ try { f.get(); } catch (Exception e) { e.printStackTrace(); } }
);
executor.shutdownNow();
System.out.println("Friend: waves send / waves received");
friends.stream().forEachOrdered(p -> System.out.println(p));
} catch (Exception e) {
e.printStackTrace();
}
}
}

Related

Thread safety count problem,Why is there a problem with counting in the code?

Why is the following code thread unsafe?
In ConcurrentHashMap, the key is the current time, the value is MutableInteger, and the mutableInteger is used for counting, and the set method and get method have been locked. Why is the final value incorrect?
public class MutableInteger {
private volatile int value;
public MutableInteger() {
}
public synchronized int getValue() {
return value;
}
public synchronized void setValue(int value) {
this.value = value;
}
}
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.concurrent.*;
public class LinkedQueue {
static ConcurrentHashMap<String,MutableInteger> map = new ConcurrentHashMap();
public static class CountQueue{
static BlockingQueue<Calendar> queue = new LinkedBlockingQueue<Calendar>();
public void produce() throws InterruptedException{
queue.put(Calendar.getInstance());
}
public Calendar consume() throws InterruptedException{
return queue.take();
}
}
/**
*/
public static void recordFlow(){
final CountQueue queue = new CountQueue();
class Producer implements Runnable {
public void run() {
try {
queue.produce();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
class Consumer implements Runnable {
public void run() {
try {
getdata(queue.consume());
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
ExecutorService service = Executors.newCachedThreadPool();
Producer producer = new Producer();
Consumer consumer = new Consumer();
service.submit(producer);
service.submit(consumer);
service.shutdown();
}
/**
*
*
* #param c 队列中取出的时间
*/
public static void getdata(Calendar c){
try{
saveFlow(c);
}catch (Exception e){
e.printStackTrace();
}
}
// 接口流量记录
public static void saveFlow(Calendar c){
System.out.println("Thread Name:"+Thread.currentThread().getName());
SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat sdfHour = new SimpleDateFormat("yyyy-MM-dd HH");
SimpleDateFormat sdfMinute = new SimpleDateFormat("yyyy-MM-dd HH:mm");
String dayAcceptKey = sdfDate.format(c.getTime());
String hourAcceptKey = sdfHour.format(c.getTime());
String minuteAcceptKey = sdfMinute.format(c.getTime());
MutableInteger newMinuteAcceptKey = new MutableInteger();
newMinuteAcceptKey.setValue(1);
MutableInteger oldMinuteAcceptKey = map.put(minuteAcceptKey, newMinuteAcceptKey);
if(null != oldMinuteAcceptKey) {
newMinuteAcceptKey.setValue(oldMinuteAcceptKey.getValue() + 1);
}
System.out.println("minute in map:"+ minuteAcceptKey + ","+ newMinuteAcceptKey.getValue());
MutableInteger newHourAcceptKey = new MutableInteger();
newHourAcceptKey.setValue(1);
MutableInteger oldHourAcceptKey = map.put(hourAcceptKey, newHourAcceptKey);
if(null != oldHourAcceptKey) {
newHourAcceptKey.setValue(oldHourAcceptKey.getValue() + 1);
}
System.out.println("hour in map:" + hourAcceptKey + "," + newHourAcceptKey.getValue());
MutableInteger newDayAcceptKey = new MutableInteger();
newDayAcceptKey.setValue(1);
MutableInteger oldDayAcceptKey = map.put(dayAcceptKey, newDayAcceptKey);
if(null != oldDayAcceptKey) {
newDayAcceptKey.setValue(oldDayAcceptKey.getValue() + 1);
}
System.out.println("day in map:" + dayAcceptKey + "," + newDayAcceptKey.getValue());
}
public static void main(String[] args){
for(int i=0;i<1000;i++) {
recordFlow();
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("==========================");
for(String key:map.keySet()){
System.out.println("key and value:" +key + " " + map.get(key).getValue());
}
}
}
The get method and set method in MutableInteger have been locked and are used ConcurrentHashMap, but the result data in the main method is incorrect. Please help me see what the problem is,thank you
You've got the same issue repeatedly, which is that you are interacting with a shared data structure in a non-synchronized way. The fact that map is a ConcurrentHashMap means that individual .get and .put calls will not break thread safety, you use multiple of those calls with the assumption that the map doesn't change between them.
MutableInteger newMinuteAcceptKey = new MutableInteger();
newMinuteAcceptKey.setValue(1);
MutableInteger oldMinuteAcceptKey = map.put(minuteAcceptKey, newMinuteAcceptKey);
// let's assume here something happens
if(null != oldMinuteAcceptKey) {
newMinuteAcceptKey.setValue(oldMinuteAcceptKey.getValue() + 1);
}
If at the point marked with a comment above some other thread also puts a new MutableInteger into the map, then your later change to newMinuteAcceptKey (which should really be newMinuteAcceptValue, since it's not the key!) will be irrelevant, as that value is no longer in the map.
In order to fix this, replace this whole thing with a single compute or merge call. Then you also don't really need MutableInteger, but can switch to a boring old Integer, if you want:
map.merge(minuteAcceptKey, 1, Integer::sum);
Those methods will do the whole operation in an atomic way, i.e. make sure that no other calls manipulate the data until they are complete.
A short summary: If you need a ConcurrentHashMap, then you almost never want to have plain .put() calls (except maybe when populating the initial values in a single-threaded way), as those method have rather weak concurrency guarantees (i.e. they only guarantee to not break the map, but any other operation can easily overwrite their values at any time).

How to make a block of code execute without interruption Java?

I'm trying to create a web crawler.
I've created a class to handle all URLs visited and to visit.
This class has to be accessed by multiple threads for retrieving and updating those lists.
The problem I'm facing, or at least I think, is in nextRandom() and probably also in next(). I think what is happening is the threads are interfering with each other since the function is somewhat synchronized but not atomic. Is there a way to make so this block of code is executed without any interruption by other threads?
The URL handler
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
public class UrlHandler {
private volatile Set<String> visited = new HashSet<String>();
private volatile List<String> toVisit = new ArrayList<String>();
public void addToVisit(String url) {
synchronized (this){
if (!visited.contains(url)) toVisit.add(url);
}
}
public void addToVisit(Collection<String> urls) {
synchronized (this){
for (String url : urls)
if (!visited.contains(url)) toVisit.add(url);
}
}
public void addVisited(String url){
synchronized (this){
visited.add(url);
}
}
public void addVisited(Collection<String> urls){
synchronized (this){
visited.addAll(urls);
}
}
public String next() {
while (toVisit.size() == 0) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
synchronized (this){
String url = toVisit.get(0);
toVisit.remove(0);
return url;
}
}
public String nextRandom() {
synchronized (this){
int n = 0;
if (toVisit.size() > 1){
n = ThreadLocalRandom.current().nextInt(toVisit.size());
}
String url = toVisit.get(n);
toVisit.remove(n);
return url;
}
}
public List<String> getToVisit() {
synchronized (this){
return toVisit;
}
}
public Set<String> getVisited() {
synchronized (this){
return visited;
}
}
}
Web Crawler
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class WebCrawler {
private final ExecutorService executor;
public WebCrawler(int nOfThreads) {
this.executor = Executors.newFixedThreadPool(nOfThreads);
}
public void add(Runnable runnable) {
this.executor.execute(runnable);
}
//Used to shut down safely and wait also 5 of seconds for not finished tasks
public void shutdown() {
this.executor.shutdown();
try {
this.executor.awaitTermination(5, TimeUnit.SECONDS);
if (!this.executor.isTerminated()) {
System.err.println("Timed out waiting for executor to terminate cleanly. Shutting down.");
this.executor.shutdownNow();
}
} catch (final InterruptedException e) {
System.err.println("Interrupted while waiting for executor shutdown.");
Thread.currentThread().interrupt();
}
}
}
Failing test example
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class UrlHandlerTest {
List<String> testList = new ArrayList<>(List.of("test1", "test2", "test3", "test3"));
List<String> uniqueTestList = new ArrayList<>(List.of("test1", "test2", "test3"));
UrlHandler urlHandler = new UrlHandler();
#Test
public void concurrentAccess(){
urlHandler.addToVisit(testList);
WebCrawler webCrawler = new WebCrawler(10);
for (int i = 0; i < urlHandler.getToVisit().size(); i++) {
webCrawler.add(new Runnable() {
#Override
public void run() {
String url = urlHandler.nextRandom();
urlHandler.addVisited(url);
System.out.println("Here thread " + Thread.currentThread().getId() + " working on: " + url);
}
});
}
webCrawler.shutdown();
System.out.println(urlHandler.getVisited());
assertEquals(true, urlHandler.getVisited().containsAll(uniqueTestList));
}
}
In the next method this code is a problem:
while (toVisit.size() == 0) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
The lock isn't held for this part, so size can be stale. Instead of this, try something like
while (toVisit.size() == 0)
wait();
Do this in a synchronized block so you have the lock held while checking the collection size. Code that adds to the collection should notify in order to wake up the waiting threads.
This piece of code is problematic:
for (int i = 0; i < urlHandler.getToVisit().size(); i++) {
webCrawler.add(new Runnable() {
// ...
});
}
The urlHandler.getToVisit().size() is always changing during the traversal, and there is uncertainty (because the size will be changed asynchronously).
Change to:
int size = urlHandler.getToVisit().size();
for (int i = 0; i < size; i++) {
webCrawler.add(new Runnable() {
// ...
});
}

java 8 completablefuture in for loop , force async to sync or like a chain

currently i have a requirement to make async task to sync in completablefuture. Eg. Task A and Task B are completablefuture. Task B runs when Task A is completed. This works fine for single time. Suppose if I make it to run in foor loop, obviously it will create n number of async calls to achieve the outcome. Because of this, i'm getting o/p like below
A
B
A
A
B
B
A
B
A
A
A
I want to achieve like
A
B
A
B
A
B
A
B
Here is the code,
package com.demo.completable.combine;
import javax.xml.stream.Location;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
public class ThenCompose {
synchronized CompletableFuture<User> getUserDetails(String name) {
return CompletableFuture.supplyAsync(() -> {
return UserService.getUser(name);
});
}
synchronized CompletableFuture<Double> getRating(User user) {
return CompletableFuture.supplyAsync(() -> {
return CreditRating.getCreditRating(user);
});
}
synchronized CompletableFuture<String> getResult(Double rating) {
return CompletableFuture.supplyAsync(()-> {
return "welcome world";
});
}
public void main() throws InterruptedException, ExecutionException {
ThenCompose cc = new ThenCompose();
// then apply
CompletableFuture<CompletableFuture<Double>> result = cc.getUserDetails("kumaran").thenApply(user -> {
return cc.getRating(user);
});
// then compose
for (int i = 1; i <= 15; i++) {
CompletableFuture<Double> taskA = cc.getUserDetails("mike").thenCompose(user -> {
System.out.println("Task A --- " +Thread.currentThread().getName() + "--" + LocalTime.now());
return cc.getRating(user);
});
CompletableFuture<String> fileLocation =
taskA.thenCompose(ts -> {
System.out.println("Task B --- " +Thread.currentThread().getName() + "--- " + LocalTime.now());
return getResult(ts);
});
}
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
ThenCompose tc = new ThenCompose();
tc.main();
}
}
putting join and get will work but I'm not supposed to use both join and get. kindly suggest a solution.
Please try below code which executes the tasks in sequence. It will give you the expected result.
static Integer methA(int seq) {
System.out.println("A-"+seq);
return seq;
}
static Integer methB(int seq) {
System.out.println("B-"+seq);
return seq;
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
System.out.println("Main started:");
CompletableFuture<Integer> ft = null;
for(int a=0;a<15;a++) {
final int seq = a;
if(ft==null) {
ft = CompletableFuture.supplyAsync(()->methA(seq))
.thenApply(s->methB(s));
}else {
ft.thenApply((s)->methA(seq))
.thenApply(s->methB(s));
}
}
ft.thenAccept(s->System.out.println("Thread completed..."+s));
System.out.println("Main ended:");
}

CyclicBarrier misunderstanding

I tried to run example with CyclicBarrier from one of tutorials:
Service man should fill empty printers when the queue of empty printers is 3.
But when I ran the code it appears that printers are filled with 2, 3 or 4 empty printers in the queue:
Printer1 is empty
Printer12 is empty
Printer14 is empty
Printer13 is empty
Filling [Printer1, Printer12, Printer14, Printer13]
Printer2 is empty
Printer7 is empty
Filling [Printer2, Printer7]
So is the example wrong or my understanding of CyclicBarrier? I consider that queue should be exactly 3 elements size. What should I add to the code to fix that? Thanks in advance.
Code:
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;
public class PrinterRecharger {
public static void main(String args[]) {
ServiceMan serviceMan = new ServiceMan(3);
for (int i = 0; i < 15; i++) {
new Thread(new Printer(serviceMan, "Printer" + (i + 1))).start();
}
}
}
class ServiceMan {
private CyclicBarrier queue;
private List<String> inQueue;
public ServiceMan(int hardWorking) {
inQueue = new ArrayList<String>();
queue = new CyclicBarrier(hardWorking, new Runnable() {
#Override
public void run() {
System.out.println("Filling " + inQueue);
inQueue.clear();
}
});
}
public void recharge(String name) {
try {
inQueue.add(name);
queue.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
class Printer implements Runnable {
private String name;
private Random rand;
private ServiceMan serviceMan;
public Printer(ServiceMan serviceMan, String name) {
this.name = name;
this.serviceMan = serviceMan;
this.rand = new Random();
}
public void run() {
try {
while (true) {
TimeUnit.SECONDS.sleep(rand.nextInt(10));
System.out.println(name + " is empty");
serviceMan.recharge(name);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Your code is thread-unsafe in several ways that I can immediately see, and probably some more which I have missed. You have data races as well as other types of race conditions.
ArrayList is not a thread-safe class, but you use it from multiple threads with no synchronization. Wrap the list into a Collections.synchronizedList() to see some improvement.
You lack any mutual exclusion between recharge() and the CyclicBarrier's action. A thread could add an item to the queue only to have it cleared away by the action.

How to implement forkjoin for a series of action which is done in for loop for now

I have a list of senders for them I have to parallely send mails individually.Currently I am iterating over the list construct the body (as it is different for different people) and then sending them. How can I use forkjoin for this. I tried using recusiveAction but I guess its only for recursive tasks.
All the examples available in internet are implemented with RecursiveAction. Is there any other class with which I can implement this.
ServiceExecutors work nicely for this. They come with Java.
import java.util.*;
import java.util.concurrent.*;
public class SendMailExample
{
public static void main(String[] args) throws Exception
{
ExecutorService executor = Executors.newFixedThreadPool(3);
Collection<Future> futures = new ArrayList<Future>();
futures.add(executor.submit(new Mailer("thread1")));
futures.add(executor.submit(new Mailer("thread2")));
futures.add(executor.submit(new Mailer("thread3")));
for (Future future : futures)
{
future.get();
}
executor.shutdown();
}
static class Mailer implements Runnable
{
private Object message;
public Mailer(Object message)
{
this.message = message;
}
public void run()
{
System.out.println("Sending message " + String.valueOf(message));
}
}
}
I browsed I got a better answer:
package Test1;
import java.util.*;
import java.util.concurrent.*;
import static java.util.Arrays.asList;
public class Sums
{
static class Sum implements Callable<Long>
{
private final long from;
private final long to;
Sum(long from, long to)
{
this.from = from;
this.to = to;
}
#Override
public Long call()
{
long acc = 0;
if(from == 0)
{
try
{
Thread.sleep(5000);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(from);
for (long i = from; i <= to; i++)
{
acc = acc + i;
}
return acc;
}
}
public static void main(String[] args) throws Exception
{
ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
List <Future<Long>> results = executor.invokeAll(asList(
new Sum(0, 10), new Sum(100, 1000), new Sum(10000, 1000000)
));
executor.shutdown();
for (Future<Long> result : results)
{
System.out.println(result.get());
}
}
}
With this code, you will be able to get the response and also any exceptions that are thrown.

Categories

Resources