Streaming data on same outputStream in multiple threads - java

I am creating a spring boot application which connects to multiple REST services and write the responses on outputStream.
I am also using multiple threads to call the REST services.
public ResponseEntity<StreamingResponseBody> startBombing(Request request) {
int numberOfThreads = request.getConfig().getNumberOfThreads() ==0?5:request.getConfig().getNumberOfThreads();
long requestPerThread = request.getConfig().getRequestPerThread() ==0 ? 100: request.getConfig().getRequestPerThread();
StreamingResponseBody responseBody = response -> {
for (int i = 1; i <= numberOfThreads; i++) {
int finalI = i;
Runnable r1 = () -> {
try {
for (int j = 1; j <= requestPerThread; j++) {
HttpRequest req = createRequest(request.getHttpRequest());
Object res = doRequest(req);
System.out.println("Thread number: " + finalI + ": " + "call number: " + j + "TimeStamp: " + System.currentTimeMillis() + ":::: RESPONSE: " + res);
response.write(("Thread number: " + finalI + ": " + "call number: " + j + "TimeStamp: " + System.currentTimeMillis() + ":::: RESPONSE: " + res).getBytes());
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
};
Thread t1 = new Thread(r1);
t1.start();
}
};
return ResponseEntity.ok()
.contentType(MediaType.TEXT_PLAIN)
.body(responseBody);
}
No data is printed on the output stream.
Any clue how to reuse same outputStream in muliple threads

Wait for all threads to finish before exiting lambda (as it will close the output for you)
StreamingResponseBody responseBody = response -> {
CountDownLatch latch=new CountDownLatch(numberOfThreads);
for (int i = 1; i <= numberOfThreads; i++) {
int finalI = i;
Runnable r1 = () -> {
try {
//ireelevant code
} finally{
latch.countDown(); // decrease latch counter
}
};
Thread t1 = new Thread(r1);
t1.start();
}
latch.await(); // wait for latch to count down to 0 + add error handling and return value
};

Related

ExecutorService with Java Streams gives this error " java.util.concurrent.ExecutionException: java.util.ConcurrentModificationException"

I have code that needs finds the N-number of optimal combinations taking exactly 1 "player" from 8 ArrayLists of "players". Each ArrayList is anywhere from 20 - 40. Which results in a huge run times with that many iterations. Before attempting to optimize run time, the code was fully functioning, just with undesirable run time. I decided the best way to do this was the use of Executor Services and Java Streams, despite me being new to both. This is a minimized version of my code below:
public static void main(String [] args){
//Lineup is an object which I store the combination of players in
ArrayList <Lineup> currBoard = new ArrayList<Lineup>();
final ExecutorService executorService = Executors.newFixedThreadPool(nThreads);
String threadId = Thread.currentThread().getName();
int tid = Integer.parseInt(threadId.substring(threadId.length() - 1));
int threadWorkLoad = newPG.size() / 4;
//int threadStart = (int)(tid - 1) * threadWorkLoad;
final List<Future<?>> futures = new ArrayList<>();
System.out.println(newPG.size());
for(int i=0; i < nThreads; i++){
Future<?> future = executorService.submit(() -> {
//System.out.println(pg.getName());
currBoard.addAll(parallelFunction(nThreads, amounts, newPG, newSG, newSF, newPF, newC, newG, newF, newL));
});
futures.add(future);
}
executorService.shutdown();
try{
executorService.awaitTermination(5000, TimeUnit.MILLISECONDS);
}catch(InterruptedException e){
System.out.println("oof");
}
try {
for (Future<?> future : futures) {
future.get(); // do anything you need, e.g. isDone(), ...
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
And here is the function which I iterate through the possible lineups
public ArrayList<Lineup> parallelFunction(int nThreads, int amounts, ArrayList<Player> newPG, ArrayList<Player> newSG, ArrayList<Player> newSF,
ArrayList<Player> newPF, ArrayList<Player> newC, ArrayList<Player> newG, ArrayList<Player> newF,
ArrayList<Player> newL) {
ArrayList<Player> temp = new ArrayList<Player>();
ArrayList<Lineup> threadBoard = new ArrayList<Lineup>();
String threadId = Thread.currentThread().getName();
int tid = Integer.parseInt(threadId.substring(threadId.length() - 1));
int threadWorkLoad = (newPG.size() + nThreads - 1) / nThreads;
int threadStart = (int)(tid - 1) * threadWorkLoad;
int threadStop = Math.min(threadStart + threadWorkLoad, newPG.size());
//ReentrantLock lock = new ReentrantLock();
ArrayList<Player> tempPG = new ArrayList<Player>();
for(int i = threadStart; i <= threadStop; i++){
tempPG.add(newPG.get(i));
}
Stream<Player> pgStream = StreamSupport.stream(tempPG.spliterator(), true);
pgStream.forEach(pg -> {
System.out.println("TID: " + tid + ", PG: " + pg.getName() + ", iterations: " + counting);
Stream<Player> sgStream = StreamSupport.stream(newSG.spliterator(), true);
sgStream.forEach(sg -> {
//System.out.println(tid + ", " + sg.getName());
Stream<Player> sfStream = StreamSupport.stream(newSF.spliterator(), true);
sfStream.forEach(sf -> {
Stream<Player> pfStream = StreamSupport.stream(newPF.spliterator(), true);
pfStream.forEach(pf -> {
Stream<Player> cStream = StreamSupport.stream(newC.spliterator(), true);
cStream.forEach(c -> {
Stream<Player> gStream = StreamSupport.stream(newG.spliterator(), true);
gStream.forEach(g -> {
if ((!(g.getName().equals(sg.getName()) || g.getName().equals(pg.getName())))
&& ((pg.getSalary() + sg.getSalary() + sf.getSalary() + pf.getSalary()
+ c.getSalary() + 3000 + 3000 + 3000) < 50000)) {
Stream<Player> fStream = StreamSupport.stream(newF.spliterator(), true);
fStream.forEach(f -> {
if ((!(f.getName().equals(sf.getName()) || f.getName().equals(pf.getName())))
&& ((g.getSalary() + pg.getSalary() + sg.getSalary() + sf.getSalary()
+ pf.getSalary() + c.getSalary() + 3000 + 3000) < 50000)) {
Stream<Player> pStream = StreamSupport.stream(newL.spliterator(), true);
pStream.forEach(p -> {
if (!(p.getName().equals(pg.getName()) || p.getName().equals(sg.getName())
|| p.getName().equals(sf.getName())
|| p.getName().equals(pf.getName())
|| p.getName().equals(c.getName())
|| p.getName().equals(g.getName())
|| p.getName().equals(f.getName()))) {
double currScore = 0;
double totalSal = 0;
totalSal = pg.getSalary() + sg.getSalary() + sf.getSalary()
+ pf.getSalary() + c.getSalary() + f.getSalary() + g.getSalary()
+ p.getSalary();
currScore = pg.getProjection() + sg.getProjection() + sf.getProjection()
+ pf.getProjection() + c.getProjection() + f.getProjection()
+ g.getProjection() + p.getProjection();
if (totalSal <= 50000.0) {
counting += 1;
temp.clear();
temp.add(pg);
temp.add(sg);
temp.add(sf);
temp.add(pf);
temp.add(c);
temp.add(g);
temp.add(f);
temp.add(p);
ArrayList<Lineup> tempBoard = new ArrayList<Lineup>();
Lineup aLine = new Lineup(temp, currScore);
if (threadBoard.size() < amounts) {
if (!alreadyIn(threadBoard, temp)) {
threadBoard.add(aLine);
}
} else if (currScore > threadBoard.get(amounts - 1).totalScore) {
// Collections.sort(currBoard, Lineup.TotComp);
if (!alreadyIn(threadBoard, temp)) {
for (int i = 0; i < threadBoard.size() - 1; i++) {
tempBoard.add(threadBoard.get(i));
}
threadBoard.clear();
threadBoard.addAll(tempBoard);
tempBoard.clear();
threadBoard.add(aLine);
}
}
Collections.sort(threadBoard, Lineup.TotComp);
}
// temp.clear();
} // p if
});
pStream.close();
} // f if
});
fStream.close();
} // g if
});
gStream.close();
});
cStream.close();
});
pfStream.close();
});
sfStream.close();
});
sgStream.close();
});
pgStream.close();
return threadBoard;
}
This causes this error after a decent amount of iterations, java.util.concurrent.ExecutionException: java.util.ConcurrentModificationException: java.util.ConcurrentModificationException
Is there anything that I did wrong with the executorService or streams to cause this.
Or does anyone have any suggestions to improve the speed of this code, as it still unsatisfactory with speed until it crashes.
Edit
main:
ArrayList<Lineup> currBoard = new ArrayList<Lineup>();
int nThreads = Runtime.getRuntime().availableProcessors();
final ExecutorService executorService = Executors.newFixedThreadPool(nThreads);
String threadId = Thread.currentThread().getName();
int tid = Integer.parseInt(threadId.substring(threadId.length() - 1));
int threadWorkLoad = newPG.size() / 4;
//int threadStart = (int)(tid - 1) * threadWorkLoad;
final List<Future<ThreadBoard>> futures = new ArrayList<Future<ThreadBoard>>();
for(int i=0; i < nThreads; i++){
Future<ThreadBoard> future = executorService.submit(() -> {
//System.out.println(pg.getName());
return parallelFunction(nThreads, amounts, newPG, newSG, newSF, newPF, newC, newG, newF, newL);
});
futures.add(future);
}
executorService.shutdown();
try{
executorService.awaitTermination(5000, TimeUnit.MILLISECONDS);
}catch(InterruptedException e){
System.out.println("oof");
}
try {
for (Future<ThreadBoard> future : futures) {
currBoard.addAll(future.get().getCurrentLineup()); // do anything you need, e.g. isDone(), ...
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
parallelFunction:
public ThreadBoard parallelFunction(int nThreads, int amounts, ArrayList<Player> newPG, ArrayList<Player> newSG, ArrayList<Player> newSF,
ArrayList<Player> newPF, ArrayList<Player> newC, ArrayList<Player> newG, ArrayList<Player> newF,
ArrayList<Player> newL) {
ThreadBoard threadBoard = new ThreadBoard();
String threadId = Thread.currentThread().getName();
int tid = Integer.parseInt(threadId.substring(threadId.length() - 1));
int threadWorkLoad = (newPG.size() + nThreads - 1) / nThreads;
int threadStart = (int)(tid - 1) * threadWorkLoad;
int threadStop = Math.min(threadStart + threadWorkLoad, newPG.size());
//ReentrantLock lock = new ReentrantLock();
ArrayList<Player> tempPG = new ArrayList<Player>();
for(int i = threadStart; i <= threadStop; i++){
tempPG.add(newPG.get(i));
}
Stream<Player> pgStream = StreamSupport.stream(tempPG.spliterator(), false);
pgStream.forEach(pg -> {
System.out.println("TID: " + tid + ", PG: " + pg.getName() + ", iterations: " + counting);
Stream<Player> sgStream = StreamSupport.stream(newSG.spliterator(), false);
sgStream.forEach(sg -> {
//System.out.println(tid + ", " + sg.getName());
Stream<Player> sfStream = StreamSupport.stream(newSF.spliterator(), false);
sfStream.forEach(sf -> {
Stream<Player> pfStream = StreamSupport.stream(newPF.spliterator(), false);
pfStream.forEach(pf -> {
Stream<Player> cStream = StreamSupport.stream(newC.spliterator(), false);
cStream.forEach(c -> {
Stream<Player> gStream = StreamSupport.stream(newG.spliterator(), false);
gStream.forEach(g -> {
if ((!(g.getName().equals(sg.getName()) || g.getName().equals(pg.getName())))
&& ((pg.getSalary() + sg.getSalary() + sf.getSalary() + pf.getSalary()
+ c.getSalary() + 3000 + 3000 + 3000) < 50000)) {
Stream<Player> fStream = StreamSupport.stream(newF.spliterator(), false);
fStream.forEach(f -> {
if ((!(f.getName().equals(sf.getName()) || f.getName().equals(pf.getName())))
&& ((g.getSalary() + pg.getSalary() + sg.getSalary() + sf.getSalary()
+ pf.getSalary() + c.getSalary() + 3000 + 3000) < 50000)) {
Stream<Player> pStream = StreamSupport.stream(newL.spliterator(), false);
pStream.forEach(p -> {
if (!(p.getName().equals(pg.getName()) || p.getName().equals(sg.getName())
|| p.getName().equals(sf.getName())
|| p.getName().equals(pf.getName())
|| p.getName().equals(c.getName())
|| p.getName().equals(g.getName())
|| p.getName().equals(f.getName()))) {
double currScore = 0;
double totalSal = 0;
totalSal = pg.getSalary() + sg.getSalary() + sf.getSalary()
+ pf.getSalary() + c.getSalary() + f.getSalary() + g.getSalary()
+ p.getSalary();
currScore = pg.getProjection() + sg.getProjection() + sf.getProjection()
+ pf.getProjection() + c.getProjection() + f.getProjection()
+ g.getProjection() + p.getProjection();
if (totalSal <= 50000.0) {
counting += 1;
ArrayList<Player> temp = new ArrayList<Player>();
temp.clear();
temp.add(pg);
temp.add(sg);
temp.add(sf);
temp.add(pf);
temp.add(c);
temp.add(g);
temp.add(f);
temp.add(p);
Lineup aLine = new Lineup(temp, currScore);
threadBoard.addLineup(aLine, currScore, amounts, temp);
// if (threadBoard.size() < amounts) {
// //if (!alreadyIn(threadBoard, temp)) {
// threadBoard.add(aLine);
// //}
// } else if (currScore > threadBoard.get(amounts - 1).totalScore) {
// // Collections.sort(currBoard, Lineup.TotComp);
// //if (!alreadyIn(threadBoard, temp)) {
// for (int i = 0; i < threadBoard.size() - 1; i++) {
// tempBoard.add(threadBoard.get(i));
// }
// threadBoard.clear();
// threadBoard.addAll(tempBoard);
// tempBoard.clear();
// threadBoard.add(aLine);
// //}
// }
//Collections.sort(threadBoard.getCurrentLineup(), Lineup.TotComp);
}
//temp.clear();
} // p if
});
pStream.close();
} // f if
});
fStream.close();
} // g if
});
gStream.close();
});
cStream.close();
});
pfStream.close();
});
sfStream.close();
});
sgStream.close();
});
pgStream.close();
return threadBoard;
}
ThreadBoard class:
public class ThreadBoard {
private List<Lineup> lineups;
public ThreadBoard(){
this.lineups = new ArrayList<>();
}
public synchronized void addLineup(Lineup aLine, double currScore, int amounts, ArrayList<Player> temp) {
if (lineups.size() < amounts) {
if (!this.alreadyIn(lineups, temp)) {
lineups.add(aLine);
}
} else if (currScore > lineups.get(amounts - 1).totalScore) {
// Collections.sort(currBoard, Lineup.TotComp);
if (!this.alreadyIn(lineups, temp)) {
lineups.set(amounts - 1, aLine);
}
}
Collections.sort(lineups, Lineup.TotComp);
}
public List<Lineup> getCurrentLineup() {
return lineups;
}
public boolean alreadyIn(List<Lineup> board, ArrayList<Player> temp) {
boolean found = false;
for (int i = 0; i < board.size(); i++) {
ArrayList <Player> check = board.get(i).getL();
boolean pg = (check.contains(temp.get(0)));
boolean sg = (check.contains(temp.get(1)));
boolean pf = (check.contains(temp.get(2)));
boolean sf = (check.contains(temp.get(3)));
boolean c = (check.contains(temp.get(4)));
boolean g = (check.contains(temp.get(5)));
boolean f = (check.contains(temp.get(6)));
boolean all = (check.contains(temp.get(7)));
if (pg && sg && pf && sf && c && g && f && all) {
found = true;
}
}
return found;
}
}
The problem with the ArrayList<Lineup> threadBoard is that it is used to collect, sort and limit the results from different parallel streams. IMHO an ArrayList is not the correct data structure for these tasks. I would create a separate class that does these steps:
public class ThreadBoard {
private List<Lineup> currentLineup = new ArrayList<>();
public void addLineup(Lineup aLine, double currScore) {
if (currentLineup.size() < amounts) {
if (!alreadyIn(currentLineup, temp)) {
currentLineup.add(aLine);
}
} else if (currScore > currentLineup.get(amounts - 1).totalScore) {
// Collections.sort(currBoard, Lineup.TotComp);
if (!alreadyIn(currentLineup, temp)) {
currentLineup.set(amounts - 1, aLine);
Collections.sort(currentLineup, Lineup.TotComp);
}
}
public List<Lineup> getCurrentLineup() {
return currentLineup;
}
}
To make this thread safe you can declare the addLineup() method as synchronized.
However I'm not sure if all those parallel streams help the performance (since you already split the complete job into chunks that are processed in parallel).
Maybe it would make more sense to split the complete job into more, smaller chunks and then use only sequential streams to process a chunk. In the end your computer has only a limited amount of cores (maybe 4, maybe 16) and splitting a CPU bound job into many more parts (and by using nested parallel streams you are doing that) than there are cores doesn't make much sense.

How to communicate with one thread from main ui thread (or any other thread)?

I'm newly working with android Thread.
I have a thread Running:
private Thread startQuery(){
return new Thread(() -> {
Handler handler = new Handler(getApplicationContext().getMainLooper());
for(int i = 1; i <= NUMBER_OF_QUERY && isThreadAlive; i++){
int tempTime = timePerQuery;
int finalI = i;
handler.post(() -> {
Random random = new Random();
int num1 = Math.abs(random.nextInt(maxNumb1)), num2 = Math.abs(random.nextInt(maxNumb2));
setCurrentResult(num1, num2);
String strNum1 = num1 + "", strNum2 = num2 + "";
txtOp.setText(typeOfOperation);
txtNumbers.setText(equalizeNumbers(strNum1, strNum2));
queryCount = finalI;
String count = "Query No: " + queryCount;
txtQueryCount.setText(count);
});
while (tempTime > 0 && isThreadAlive){
int sec = tempTime/1000,
min = sec/60;
int sec1 = sec%60;
String s = min + " : " + sec1;
txtRemainingTime.setText(s);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
tempTime -= 1000;
}
}
});
}
This thread is making values for variable "currentResult" in each iteration. Now
I want to use the value of "currentResult" from Main Thread on Clicking a button like this:
if(id == R.id.game_btnSubmit){
String strInput = edtUserResultInput.getText().toString();
if(strInput.isEmpty()){
edtUserResultInput.setError("Enter Result");
edtUserResultInput.requestFocus();
return;
}
double input = Double.parseDouble(strInput);
if(currentResult == input){
isRight[queryCount] = 1;
Toast.makeText(this, "Correct", Toast.LENGTH_LONG).show();
}
else{
isRight[queryCount] = 0;
Toast.makeText(this, "Wrong", Toast.LENGTH_LONG).show();
}
}
But the problem is, after clicking the button My app gets freeze.
Why?
Where is the problem or what is the solution?
I'm stuck with this.
Thank you <3

ReentrantLock tryLock(timeout,timeUnit) doesn't work as expected

I have some confuse about ReentrantLock tryLock(timeout,timeUnit) method , when
running below code it seems tryLock timeout until the previous thread end,could anyone explains this?
public class MyService2 {
public ReentrantLock lock = new ReentrantLock();
public void waitMethod() {
try {
System.out.println(System.currentTimeMillis() + " " + Thread.currentThread().getName() + " enter ");
boolean b = lock.tryLock(2, TimeUnit.SECONDS);
if (b) {
System.out.println(System.currentTimeMillis() + " lock begin:" + Thread.currentThread().getName());
for (int i = 0; i < Integer.MAX_VALUE / 10; i++) {
Math.random();
}
System.out.println(System.currentTimeMillis() + " lock end " + Thread.currentThread().getName());
return;
}
System.out.println(System.currentTimeMillis() + " " + Thread.currentThread().getName() + " got no lock end ");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
public static void main(String[] args) throws InterruptedException {
MyService2 myService2 = new MyService2();
Runnable runnable = myService2::waitMethod;
Thread thread1 = new Thread(runnable);
thread1.setName("T1");
thread1.start();
TimeUnit.MILLISECONDS.sleep(10);
Thread thread2 = new Thread(runnable);
thread2.setName("T2");
thread2.start();
}
after running this code ,the result is like that
1555343172612 T1 enter
1555343172613 lock begin:T1
1555343172627 T2 enter
1555343179665 lock end T1
1555343179665 T2 got no lock end
my question is why thread T2 doesn't timeout in 2s rather than waiting until thread T1 ends?
BUT I just found:
if replace Math.random() with TimeUnit.SECONDS.sleep(1) for example ,it works fine.
if run in debug mode ,it works fine too.
Here is an alternate which has a number modifications:
First, cleanups. Clearer names. Less intrusive logging. Relative time values.
Second, the 0.1s sleep between the launch of the two compute threads is moved into each of the threads. That more clearly gives precedence to the thread which launches the compute threads.
Third, the launch thread has joins with the compute threads. That is to tie the conclusion of the computation to the launch thread. In the original code, there is no management of the compute threads after they have been launched. If the compute threads are intended to be unmanaged, that needs to be documented.
Fourth, the entire launch thread plus two compute threads structure is replicated. That is to place give the structure a more realistic runtime environment, and, to present the different behaviors of the structure together in a single view.
A theme to the modifications is to provide clarity, both to the intended behavior of the program, and to the actual behavior (as viewed through the logging output). The goal is to provide maximal clarity to these.
An additional modification is recommended, which is to put the log statements into a cache, then display the collected log lines after all of the computation cells have completed. That removes behavior changes caused by the log statements, which are often considerable.
package my.tests;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
public class LockTest {
private static long initialTime;
protected static void setInitialTime() {
initialTime = System.currentTimeMillis();
}
public static long getInitialTime() {
return initialTime;
}
public static final int CELL_COUNT = 10;
public static void main(String[] args) {
setInitialTime();
System.out.println("Beginning [ " + Integer.toString(CELL_COUNT) + " ] computation cells");
Thread[] cellThreads = new Thread[CELL_COUNT];
for ( int cellNo = 0; cellNo < CELL_COUNT; cellNo++ ) {
final String cellNoText = Integer.toString(cellNo);
Runnable computeCell = () -> {
(new LockTest(cellNoText) ).compute();
};
Thread cellThread = new Thread(computeCell);
cellThreads[cellNo] = cellThread;
}
// Start them all up ...
for ( Thread cellThread : cellThreads ) {
cellThread.start();
}
// Then wait for them all to finish ...
for ( Thread cellThread : cellThreads ) {
try {
cellThread.join();
} catch ( InterruptedException e ) {
System.out.println("Unexpected interruption: " + e.getMessage());
e.printStackTrace();
}
}
System.out.println("Completed [ " + Integer.toString(CELL_COUNT) + " ] computation cells");
}
//
public LockTest(String cellName) {
this.cellName = cellName;
}
private final String cellName;
public String getCellName() {
return cellName;
}
// Logging ...
public String formatTime(long timeMs) {
return String.format("%12d (ms)", new Long(timeMs));
}
public long getRelativeTime(long currentTime) {
return currentTime - getInitialTime();
}
public String formatRelativeTime(long timeMs) {
return String.format(
"%12d %8d (ms)",
new Long(timeMs),
new Long( timeMs - getInitialTime() ));
}
public void log(String methodName, String message) {
long timeMs = System.currentTimeMillis();
String threadName = Thread.currentThread().getName();
System.out.println(
formatRelativeTime(timeMs) + ": " +
methodName + ": " +
threadName + ": " + message);
}
//
public void compute() {
log("compute", "ENTER: " + getCellName());
Runnable computation = () -> {
guardedComputation(
100L, 0, // Pause 0.1s before attempting the computation
1, TimeUnit.SECONDS, // Try to obtain the computation lock for up to 1.0s.
Integer.MAX_VALUE / 60 ); // Run this many computations; takes about 2s; adjust as needed
};
Thread computer1 = new Thread(computation);
computer1.setName( getCellName() + "." + "T1");
Thread computer2 = new Thread(computation);
computer2.setName( getCellName() + "." + "T2");
// Run two sets of computations:
//
// Each will pause for 0.1s before performing the computations.
//
// Performing computations requires a computation lock; wait up to 2.0s
// to acquire the lock.
computer1.start();
computer2.start();
try {
computer1.join();
} catch ( InterruptedException e ) {
System.out.println("Unexpected interruption: " + e.getMessage());
e.printStackTrace();
return;
}
try {
computer2.join();
} catch ( InterruptedException e ) {
System.out.println("Unexpected interruption: " + e.getMessage());
e.printStackTrace();
return;
}
log("compute", "RETURN: " + getCellName());
}
// Computation locking ...
private final ReentrantLock computationLock = new ReentrantLock();
public boolean acquireComputationLock(long maxWait, TimeUnit maxWaitUnit) throws InterruptedException {
return computationLock.tryLock(maxWait, maxWaitUnit);
}
public void releaseComputationLock() {
if ( computationLock.isHeldByCurrentThread() ) {
computationLock.unlock();
}
}
//
public void guardedComputation(
long pauseMs, int pauseNs,
long maxWait, TimeUnit maxWaitUnit, int computations) {
String methodName = "guardedComputation";
log(methodName, "ENTER");
try {
Thread.sleep(pauseMs, pauseNs);
} catch ( InterruptedException e ) {
System.out.println("Unexpected interruption: " + e.getMessage());
e.printStackTrace();
return;
}
try {
boolean didLock;
try {
didLock = acquireComputationLock(maxWait, maxWaitUnit);
} catch ( InterruptedException e ) {
System.out.println("Unexpected interruption: " + e.getMessage());
e.printStackTrace();
return;
}
String computationsText = Integer.toString(computations);
if ( didLock ) {
log(methodName, "Starting computations: " + computationsText);
for ( int computationNo = 0; computationNo < computations; computationNo++ ) {
Math.random();
}
log(methodName, "Completed computations: " + computationsText);
} else {
log(methodName, "Skipping computations: " + computationsText);
}
} finally {
releaseComputationLock();
}
log(methodName, "RETURN");
}
}

How to find method which call threadPool

I have some bug in production's application, but I can't find the cause of it. I try to get some log to find a method, which calls my method(). But because I use threadPool I can't just get Thread.currentThread().getStackTrace() and iterate through StackTraceElements, it shows only some lines before ThreadPool.
If I use the next code, I'll get every method which I need, but it so expansive. Only 1 call of method cost 400+ Kb in a text file in my test environment. In production it would be about 1 Mb in a second, I think.
private final ExecutorService completableFutureExecutor =
new ThreadPoolExecutor(10, 2000, 60L, TimeUnit.SECONDS, new SynchronousQueue<>());
public void firstMethod(){
secondMethod();
}
private CompletableFuture<Void> secondMethod(){
return CompletableFuture.supplyAsync(()->method(),threadPool);
}
void method(){
Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces();
for (Thread thread : map.keySet()) {
printLog(thread);
}
}
private void printLog(Thread thread) {
StringBuilder builder = new StringBuilder();
for (StackTraceElement s : thread.getStackTrace()) {
builder.append("\n getClass = " + s.getClass());
builder.append("\n getClassName = " + s.getClassName());
builder.append("\n getFileName = " + s.getFileName());
builder.append("\n getLineNumber = " + s.getLineNumber());
builder.append("\n getMethodName = " + s.getMethodName());
builder.append("\n ---------------------------- \n ");
}
ownLogger.info("SomeThread = {} ", builder);
}
How to find that firstMethod() who calls secondMethod() ?
As I haven't found any good solution my own is to put logger before and after CompletableFuture call
It looks like
Logger beforeAsync= LoggerFactory.getLogger("beforeAsync");
Logger afterAsync= LoggerFactory.getLogger("afterAsync");
private CompletableFuture<Void> secondMethod(){
printLongerTrace(Thread.currentThread(),beforeAsync);
return CompletableFuture.supplyAsync(()->method(),threadPool);
}
private void methodWithException(){
try{
//do something
}
catch(Exception e){
printLongerTrace(e,"methodWithException", afterAsync);
}
}
public void printLongerTrace(Throwable t, String methodName, Logger ownlogger) {
if (t.getCause() != null) {
printLongerTrace(t.getCause(), methodName, fields, ownlogger);
}
StringBuilder builder = new StringBuilder();
builder.append("\n Thread = " + Thread.currentThread().getName());
builder.append("ERROR CAUSE = " + t.getCause() + "\n");
builder.append("ERROR MESSAGE = " + t.getMessage() + "\n");
printLog(t.getStackTrace(), builder);
ownlogger.info(methodName + "Trace ----- {}", builder);
}
public void printLongerTrace(Thread t, Logger ownlogger) {
StringBuilder builder = new StringBuilder();
builder.append("\n Thread = " + Thread.currentThread().getName());
printLog(t.getStackTrace(), builder);
ownlogger.info("Trace ----- {}", builder);
}
private StringBuilder printLog(StackTraceElement[] elements, StringBuilder builder) {
int size = elements.length > 15 ? 15 : elements.length;
for (int i = 0; i < size; i++) {
builder.append("Line " + i + " = " + elements[i] + " with method = " + elements[i].getMethodName() + "\n");
}
return builder;
}
printLongerTrace(Throwable t, String methodName, Logger ownlogger) needs to print exception with every cause in recursion.
printLongerTrace(Thread t, Logger ownlogger) needs to print which method call before CompletableFuture
Just dump the Stack by calling Thread.dumpStack() but this is only for debugin and has a big overhead, since dumping the stack is cpu intensive

about effective java 2 char 10 item 66

public class StopMultiThread {
private static boolean stopRequested;
public static void main(String[] args) throws InterruptedException {
int testNum = 100;
List<Boolean> result = new ArrayList<>(testNum);
CountDownLatch countDownLatch = new CountDownLatch(testNum);
for (int i = 0; i < testNum; i++) {
int copy = i;
Thread backgroundThread = new Thread(new Runnable() {
#Override
public void run() {
long beginTime = System.currentTimeMillis();
int j = 0;
while (!stopRequested) {
// j++;
System.out.println("brokenStopMultiThread " + copy + " " + j++);
}
long runTime = System.currentTimeMillis() - beginTime;
System.out.println("brokenStopMultiThread " + copy + " run " + runTime);
result.add(runTime < 1500);
countDownLatch.countDown();
}
});
backgroundThread.start();
}
TimeUnit.SECONDS.sleep(1);
stopRequested = true;
countDownLatch.await();
System.out.println("result:" + result);
int expectedTimes = 0;
for (Boolean b : result)
if (b)
expectedTimes++;
System.out.println("expectedTimes:" + expectedTimes + ", brokenTimes:" + (result.size() - expectedTimes));
}
}
enviroment
java version "1.8.0_77"
Java(TM) SE Runtime Environment (build 1.8.0_77-b03)
Java HotSpot(TM) 64-Bit Server VM (build 25.77-b03, mixed mode)
code above can stop thread normally, but code below can not, why?
while (!stopRequested) {
j++;
// System.out.println("brokenStopMultiThread " + copy + " " + j++);
}
test 5 times
code A will result in
expectedTimes:23, brokenTimes:977
expectedTimes:45, brokenTimes:955
expectedTimes:174, brokenTimes:825
expectedTimes:207, brokenTimes:793
expectedTimes:175, brokenTimes:825
code A
while (!stopRequested) {
try {
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
j++;
// System.out.println("brokenStopMultiThread " + copy + " " + j++);
}
code B will result in
expectedTimes:1000, brokenTimes:0
expectedTimes:999, brokenTimes:0
expectedTimes:1000, brokenTimes:0
expectedTimes:1000, brokenTimes:0
expectedTimes:1000, brokenTimes:0
code B
while (!stopRequested) {
/*try {
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
j++;*/
System.out.println("brokenStopMultiThread " + copy + " " + j++);
}
all threads are stopped with different runTime, maybe liveness failure does not occur easily on jdk8

Categories

Resources