I've got a method in a tools class that should detect the existence of a deadlock during runtime:
/**
* Returns a list of thread IDs that are in a deadlock
* #return the IDs or <code>null</code> if there is no
* deadlock in the system
*/
public static String[] getDeadlockedThreads() {
ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
long[] vals = threadBean.findDeadlockedThreads();
if (vals == null){
return null;
}
String[] ret = new String[vals.length];
for (int i = 0; i < ret.length; i++){
ret[i] = Long.toString(vals[i]);
}
return ret;
}
I created a JUnit test that tests that functionality. It works well on Windows but on a Linux system the test fails 8 times out of 10. This is my test code:
/**
* Tests the correct functionality of the get deadlock info functionality
*
* #throws Exception Will be thrown if there was an error
* while performing the test
*/
public void testGetDeadlockInformation() throws Exception {
assertNull("check non-existance of deadlock", ThreadUtils.getDeadlockedThreads());
final String monitor1 = "Monitor1";
final String monitor2 = "Monitor2";
Thread[] retThreads = createDeadlock(monitor1, monitor2, this);
String[] res = ThreadUtils.getDeadlockedThreads();
assertNotNull("check existance of returned deadlock info", res);
assertEquals("check length of deadlock array", 2, res.length);
retThreads[0].interrupt();
retThreads[0].interrupt();
Thread.sleep(100);
res = ThreadUtils.getDeadlockedThreads();
assertNotNull("check existance of returned deadlock info", res);
assertEquals("check length of deadlock array", 2, res.length);
}
/**
* Creates a deadlock
*
* #param monitor1 monitor 1 that will be used for synchronization
* #param monitor2 monitor 2 that will be used for synchronization
* #param waitMonitor The monitor to be used for internal synchronization
* #return The threads that should be deadlocked
* #throws InterruptedException Will be thrown if there was an error
* while setting up the deadlock
*/
public static Thread[] createDeadlock(final String monitor1, final String monitor2, Object waitMonitor) throws InterruptedException {
DeadlockThread dt1 = new DeadlockThread(monitor1, monitor2, waitMonitor);
DeadlockThread dt2 = new DeadlockThread(monitor2, monitor1, waitMonitor);
DeadlockThread[] retThreads = new DeadlockThread[] {
dt1,
dt2,
};
synchronized (waitMonitor) {
dt1.start();
waitMonitor.wait(1000);
dt2.start();
waitMonitor.wait(1000);
}
synchronized (monitor1) {
synchronized (monitor2) {
monitor1.notifyAll();
monitor2.notifyAll();
}
}
Thread.sleep(4000);
return retThreads;
}
private static class DeadlockThread extends Thread {
private String monitor1;
private String monitor2;
private Object waitMonitor;
public DeadlockThread(String monitor1, String monitor2, Object waitMonitor) {
this.monitor1 = monitor1;
this.monitor2 = monitor2;
this.waitMonitor = waitMonitor;
setDaemon(true);
setName("DeadlockThread for monitor " + monitor1 + " and " + monitor2);
}
#Override
public void run() {
System.out.println(getName() + ": Running");
synchronized (monitor1) {
System.out.println(getName() + ": Got lock for monitor '" + monitor1 + "'");
synchronized (waitMonitor) {
waitMonitor.notifyAll();
}
try {
System.out.println(getName() + ": Waiting to get lock on '" + monitor2 + "'");
monitor1.wait(5000);
System.out.println(getName() + ": Try to get lock on '" + monitor2 + "'");
synchronized (monitor2) {
monitor2.wait(5000);
}
System.out.println(getName() + ": Got lock on '" + monitor2 + "', finished");
} catch (Exception e) {
// waiting
}
}
}
}
This is the output when running the testcase:
DeadlockThread for monitor Monitor1 and Monitor2: Running
DeadlockThread for monitor Monitor1 and Monitor2: Got lock for monitor 'Monitor1'
DeadlockThread for monitor Monitor1 and Monitor2: Waiting to get lock on 'Monitor2'
DeadlockThread for monitor Monitor2 and Monitor1: Running
DeadlockThread for monitor Monitor2 and Monitor1: Got lock for monitor 'Monitor2'
DeadlockThread for monitor Monitor2 and Monitor1: Waiting to get lock on 'Monitor1'
DeadlockThread for monitor Monitor1 and Monitor2: Try to get lock on 'Monitor2'
DeadlockThread for monitor Monitor2 and Monitor1: Try to get lock on 'Monitor1'
According to the output there should be a deadlock, so either the way I try to detect deadlocks is wrong or something else, I'm missing here, doesn't work as I expect it. But then, the test should fail all the time and not only most of the time.
When running the test on Windows, the output is the same.
Just a guess. Your use of Thread.sleep() seems highly dubious. Try using some form of communication to determine with both threads are ready to be deadlocked.
Untested:
private Thread[] creadDeadlock() throws InterruptedException {
Thread[] deadLocked = new Thread [2];
CountDownLatch gate = new CountDownLatch( 2 );
CountDownLatch ready = new CountDownLatch( 2 );
Object monitor1 = new Object();
Object monitor2 = new Object();
Runnable r1 = () -> {
synchronized( monitor1 ) {
try {
gate.countDown();
gate.await();
ready.countDown();
synchronized( monitor2 ) {
wait();
}
} catch( InterruptedException ex ) {
// exit
}
}
};
Runnable r2 = () -> {
synchronized( monitor2 ) {
try {
gate.countDown();
gate.await();
ready.countDown();
synchronized( monitor1 ) {
wait();
}
} catch( InterruptedException ex ) {
// exit
}
}
};
deadLocked[0] = new Thread( r1 );
deadLocked[1] = new Thread( r2 );
deadLocked[0].start();
deadLocked[1].start();
ready.await();
return deadLocked;
}
Related
My requirement is to encrypt personal identification columns of table. For which I have written a small code which selects the data in batches and insert into new table with few extra columns.
Problem is when i run my code , it works good in begining but stops inserting record in db. It does not print any exception as well.
This is my connection pool config.
private BlockingQueue<EntityManager> getConnectionPool(int poolSize) throws InterruptedException {
// List<EntityManager> list = new ArrayList<>();
BlockingQueue<EntityManager> queue = new ArrayBlockingQueue<>(poolSize);
int i = poolSize;
do
{
EntityManager entityManager = connectionService.getEm();
queue.put(entityManager);
//list.add(entityManager);
i--;
}
while (i != 0);
return queue;
}
This is the class from where everything starts. It calculates the total number of batches and calls one method for executor service.
public void insertData() throws InterruptedException {
key = hash(key);
EntityManager entityManager = connectionService.getEm();
EntityTransaction entityTransaction = entityManager.getTransaction();
BlockingQueue<EntityManager> queue = getConnectionPool( 200);
try {
int batchSize= 1000;
BigInteger totalResults = partnerRepository.getCountCustomerLedger(entityManager);
double totalPages = Math.ceil(totalResults.longValue() / batchSize);
int maxResult = batchSize;
CountDownLatch latch = new CountDownLatch(((Double)totalPages).intValue());
for(int i =1 ; i <= totalPages; i++) {
int firstResult = (i - 1) * batchSize;
if (i == totalPages)
{
batchSize = totalResults.intValue() - firstResult;
}
exectueTask(queue, firstResult, batchSize, latch, i);
}
System.out.println("waiting for latch to finish");
latch.await();
System.out.println("latch exited");
}catch (Exception e) {
e.printStackTrace();
if (entityTransaction.isActive()) {
entityTransaction.rollback();
}
entityManager.close();
}
finally {
int i = poolSize;
do
{
queue.take().close();
i--;
}
while (i != 0);
}
entityManager.close();
}
This calls the executor method
private void exectueTask(BlockingQueue<EntityManager> queue, int firstResult, int batchSize, CountDownLatch latch, int batchNumber) {
taskExecutor.execute(() -> {
try {
try {
run(queue, firstResult, batchSize, latch, batchNumber);
} catch (IOException e) {
e.printStackTrace();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
Here I executing queries in batches and inserting data into db
private void run(BlockingQueue<EntityManager> queue, int firstResult, int batchSize, CountDownLatch latch, int batchNumber) throws InterruptedException, IOException {
logger.info("batchNumber " + batchNumber + " batchNumber called " + " at " + new Date());
EntityManager entityManager = queue.take();
logger.info("batchNumber " + batchNumber + " batchNumber took " + " following time to get entitymanager " + new Date());
EntityTransaction entityTransaction = entityManager.getTransaction();
List<CustomerLedger> customerLedgerList = partnerRepository.getAllCustomerLedger(entityManager,firstResult, batchSize);
//List<Object[]> customerLedgerList = partnerRepository.getAllCustomerLedgerNative(entityManager,firstResult, batchSize);
entityTransaction.begin();
for (CustomerLedger old :customerLedgerList) {
CustomerLedgerNew ledgerNew = new CustomerLedgerNew();
String customerLedgerJson = objectMapper.writeValueAsString(old);
ledgerNew = customerLedgerToCustomerLedgerNew(customerLedgerJson);
ledgerNew.setFirstName(convertToDatabaseColumn(old.getFirstName(),key));
ledgerNew.setMiddleName(convertToDatabaseColumn(old.getMiddleName(),key));
ledgerNew.setLastName(convertToDatabaseColumn(old.getLastName(),key));
ledgerNew.setAddressLine1(convertToDatabaseColumn(old.getAddressLine1(),key));
ledgerNew.setAddressLine2(convertToDatabaseColumn(old.getAddressLine2(),key));
ledgerNew.setAddressLine3(convertToDatabaseColumn(old.getAddressLine3(),key));
ledgerNew.setAddressLine4(convertToDatabaseColumn(old.getAddressLine4(),key));
ledgerNew.setHomePhone(convertToDatabaseColumn(old.getHomePhone(),key));
ledgerNew.setWorkPhone(convertToDatabaseColumn(old.getWorkPhone(),key));
ledgerNew.setEmail1(convertToDatabaseColumn(old.getEmail1(),key));
ledgerNew.setMobile(convertToDatabaseColumn(old.getMobile(),key));
ledgerNew.setMobileSha(sha256Hash(old.getMobile()));
ledgerNew.setMobileChecksum(getMD5Hash(old.getMobile()));
ledgerNew.setEmailSha(sha256Hash(old.getEmail1()));
ledgerNew.setEmailChecksum(getMD5Hash(old.getEmail1()));
//ledgerNew.setChannel(old.getChannel());
//ledgerNew.setUniqueCustomerId(old.getUniqueCustomerId());
//ledgerNew.setLastModifiedDate(old.getLastModifiedDate());
entityManager.persist(ledgerNew);
}
//System.out.println("commited");
logger.info("batchNumber " + batchNumber + " batchNumber started commiting data at " + new Date());
entityTransaction.commit();
logger.info("batchNumber " + batchNumber + " batchNumber finished commiting data at " + new Date());
queue.put(entityManager);
latch.countDown();
logger.info("batchNumber " + batchNumber + " latch count " + latch.getCount());
}
what I noticed from the logs , at one point It only print the logs
** batchNumber 615 batchNumber started commiting data at Wed Dec 11 17:22:54 IST 201** but does not print the next line logs of commiting data. I am really unable to get this reason.
Thread pool config class
#Configuration
public class ThreadPoolConfiguration {
private final static org.slf4j.Logger LOGGER = org.slf4j.LoggerFactory.getLogger(ThreadPoolConfiguration.class);
private final int defaultCorePoolSize = 200;
private final int defaultMaxPoolSize = 300;
private final int defaultQueueCapacity = 20000;
private final int defaultKeepAlive = 10;
#Bean
#Qualifier("TaskExecutor")
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(defaultCorePoolSize);
executor.setMaxPoolSize(defaultMaxPoolSize);
executor.setQueueCapacity(defaultQueueCapacity);
executor.setKeepAliveSeconds(defaultKeepAlive);
executor.setAllowCoreThreadTimeOut(true);
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setThreadNamePrefix("encryption-DEFAULT-");
executor.initialize();
return executor;
}
}
Please forgive me If I am unable to frame it properly
There are multiple possible sources for your problem:
* MySQL table locking deadlock
* MySQL running out of connections (check MySQL logs)
* Out-of-memory situations due to overfull EntityManager buffers
* Deadlock in EntityManager
Since your problem arises when you call entityTransaction.commit(), I'd presume you have a problem with table locking deadlocks. Take a look at this article to analyse posible MySQL deadlock problems.
Your approach looks to me as if you've been working for quite some time on the performance this batch update. Working with multiple threas will give the database a hard time doing table/record locking while not gaining much performance.
I'd recommend doing big batches of work not with an entity manager, but JDBC.
If you have to use JPA, better optimize on the batch size. Take a look at The best way to do batch processing with JPA and Hibernate to get more inspirations.
I have generating data of users with auto-increment ID, then write it to file following these rules:
Name the file in following structure (FileCounter)_(StartID)_(EndID)
Maximum 1000 records per file
If don't have enough 1000 records to write, wait maximum 10s, if any added, write it all to file otherwise, write the remain list to file (not enough 1000), if nothing to write after wait, create empty file with naming (FileCounter)_0_0
My approach is using 2 thread, 1 thread to generate data then push it to the queue, 1 thread to take from the queue add to a list then write the list to the file.
//Generate function
public void generatedata() {
int capacity = 1678;
synchronized(users) {
for(int index = 0; index <capacity; index++) {
users.add(generateUser());
// notify to read thread
users.notifyAll();
}
}
//Write function
public void writeToFile(ArrayList<User> u) {
String fileName ="";
if(!u.isEmpty()) {
String filename = "" + (++FileCounter) + "_"+ u.get(0).getId() + "_" +
u.get(u.size() - 1).getId() + ".txt";
try {
FileWriter writer = new FileWriter(filename, true);
for (User x : u) {
System.out.println(x.toString());
writer.write(x.getId() + " | " + x.getFormatedDate() + " | " +
x.getSex() + " | " + x.getPhoneNum().getPhoneNumber() + " | " +
x.getPhoneNum().getProvider() + "\r\n");
}
writer.close();
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else {
try {
fileName = ""+(++FileCounter) +"_0_0.txt";
File f = new File(fileName);
f.createNewFile();
} catch (IOException ex) {
Logger.getLogger(UsersManager.class.getName()).log(Level.SEVERE,
null, ex);
}
}
}
//Read function
public ArrayList<User> ReadFromQueue(ArrayList<User> u) {
while(true) {
try {
int size = users.size();
if(users.isEmpty() && u.size() < 1000) {
users.wait(10000);
if(isChanged(size)) {
System.out.println("Size changed here");
u.add(users.take());
}
else return u;
}
if(u.size() == 1000) {
System.out.println("Check the size is 1000");
return u;
}
u.add(users.take());
} catch (InterruptedException ex) {
Logger.getLogger(UsersManager.class.getName()).log(Level.SEVERE,
null, ex);
}
}
It work fine when I run 1 thread to generate data, 1 thread to read then write data to file but when I use 2++ thread for each generate thread of write thread, There are 1 problems :
The list written in the file still has 1000 records as expected but not sequential at all, it only ascending order.
My output is like:
1_2_1999.txt
2_1_2000.txt
3_2001_3000.txt
My expected output is like:
1_1_1000.txt
2_1001_2000.txt
....
Thanks in advance!
using the thread approach is best for when you do not want to control the amount per file. but since you have a constraint of 1000 records, it's probably easier to use a counter;
public class DataReaderWriter(){
//keeps track of where you left off at, which row in source data.
static int currentRowInSourceData = 0;
public static void main(String[] args){
List<ContactRecord> contacts = getMoreData();
writeRecords(contacts);
}
writeRecords(List<ContactRecord> contacts){
int maxRecords = currentRowInSourceData+1000;
for(int i = currentRowInSourceData;i<maxRecords;i++){
ContactRecord c = contacts.get(i);
writeToFile(c);
currentRowInSourceData++;
}
}
I had a project where I needed to create 90 second previews from larger MP4 files. What I did was to have multiple threads start up with access to a shared Queue of file names. Each thread consumes work from the Queue by using queue.poll().
Here is the Constructor:
public Worker(Queue<String> queue, String conferenceYear, CountDownLatch startSignal, CountDownLatch doneSignal) {
this.queue = queue;
this.startSignal = startSignal;
this.doneSignal = doneSignal;
}
Then, as I said above, I keep polling for data:
public void run() {
while (!queue.isEmpty()) {
String fileName = queue.poll() + ".mp4";
File f = new File("/home/ubuntu/preview_" + fileName);
if (fileName != null && !f.exists()) {
System.out.println("Processing File " + fileName + "....");
I started these threads in another class called WorkLoad:
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
BlockingQueue<String> filesToDownload = new LinkedBlockingDeque<String>(1024);
BlockingQueue<String> filesToPreview = new LinkedBlockingDeque<String>(1024);
BlockingQueue<String> filesToUpload = new LinkedBlockingDeque<String>(1024);
for (int x = 0; x < NUMBER_OF_THREADS; x++) {
workers[x] = new Thread(new Worker(filesToPreview, currentYear, startSignal, doneSignal));
workers[x].start();
}
In your specific case, you could provide each thread its own file name, or a handle on a file. If you want the file names and entries in a chronological sequence, then just start 2 threads, 1 for acquiring data and placing on a queue, with a barrier/limit of 1000 records, and the other thread as a consumer.
the original code creates multiple threads. I am able to create 90 second snippets from over 1000 MP4 videos in about 30 minutes.
Here I am creating a thread per processor, I usually end up with at least 4 threads on my AWS EC2 instance:
/**
* Here we can find out how many cores we have.
* Then make the number of threads NUMBER_OF_THREADS = the number of cores.
*/
NUMBER_OF_THREADS = Runtime.getRuntime().availableProcessors();
System.out.println("Thread Count: "+NUMBER_OF_THREADS);
for (int x = 0; x < NUMBER_OF_THREADS; x++) {
workers[x] = new Thread(new MyClass(param1, param2));
workers[x].start();
}
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");
}
}
This question already has answers here:
How to wait for all threads to finish, using ExecutorService?
(27 answers)
Closed 4 years ago.
I am using executor service to run my 10 tasks with 2 tasks at a time.
ExecutorService executor = Executors.newFixedThreadPool(2);
for (int i = 0; i < 10; i++) {
String name = "NamePrinter " + i;
Runnable runner = new TaskPrint(name, 1000);
System.out.println("Adding: " + name + " / " + 1000);
executor.execute(runner);
}
How can I wait for all tasks to complete
Use java 8 CompleteableFuture with join method to wait:
ExecutorService executor = Executors.newFixedThreadPool(2);
CompletableFuture[] futures = new CompletableFuture[10];
for (int i = 0; i < 10; i++) {
String name = "NamePrinter " + i;
Runnable runner = new TaskPrint(name, 1000);
System.out.println("Adding: " + name + " / " + 1000);
futures[i] = CompletableFuture.runAsync(runner, executor);
}
CompletableFuture.allOf(futures).join(); // THis will wait until all future ready.
Assign your callables to futures and check that you can get results from each future.
Future future = workerExecutor.submit(new Callable() {
#Override
public Object call() throws Exception {
try {
System.out.println("MyItemTree.TimedRunnable");
ReturnInterface returnInterface = (ReturnInterface) commandInterface.call();
returnInterface.submitResult();
} catch (Exception ex) {
ex.printStackTrace();
throw new RuntimeException(ex);
}
return null;
}
});
try {
Object get = future.get();
} catch (InterruptedException | ExecutionException ex) {
Throwable cause = ex.getCause();
ex.printStackTrace();
cause.printStackTrace();
Throwable cause1 = cause.getCause();
if (cause1 instanceof CommandInterfaceException) {
System.out.println("[MyItemTree].scheduleTask Cause 1= COMMANDINTERFACE EXCEPTION");
this.componentInterface.getAlertList().addAlert(((CommandInterfaceException) cause1).getResolverFormInterface());
}
}
}
This question already has answers here:
How do I compare strings in Java?
(23 answers)
Closed 8 years ago.
I am quite new to concurrent programming and I am enjoying it so far :)! However I just realized how tricky concurrent programming.
I have multiple threads which perform their own computations. Each thread operates on a certain variable and returns a result, however the result returned is incorrect.
This class performs the thread calculations:
public class SharedDataThread extends Thread {
private SharedData mySharedData;
private String myThreadName;
private static long testVariable = 0;
// Setup the thread
SharedDataThread(String name, SharedData sharedstuff) {
super(name);
mySharedData = sharedstuff;
myThreadName = name;
}
public void run() {
System.out.println(myThreadName + " is running");
Thread me = Thread.currentThread(); // get a ref to the current thread
if (me.getName() == "myThread1") {
try {
sleep(2000);
mySharedData.acquireLock();
System.out.println(me.getName()
+ " is performing computations!");
testVariable = testVariable + 20;
testVariable = testVariable * 5;
testVariable = testVariable / 3;
System.out.println(me.getName() + " modified the value to : "
+ testVariable + "\n");
sleep(2000);
mySharedData.releaseLock();
} catch (InterruptedException e) {
System.err.println("Failed to get lock when reading:" + e);
}
} else if (me.getName() == "myThread2") {
try {
sleep(2000);
mySharedData.acquireLock();
System.out.println(myThreadName
+ " is performing computations!");
testVariable = testVariable - 5;
testVariable = testVariable * 10;
testVariable = (long) (testVariable / 2.5);
System.out.println(me.getName() + " modified the value to : "
+ testVariable + "\n");
sleep(2000);
mySharedData.releaseLock();
} catch (InterruptedException e) {
System.err.println("Failed to get lock when reading:" + e);
}
} else if (me.getName() == "myThread3") {
try {
sleep(2000);
mySharedData.acquireLock();
System.out.println(me.getName()
+ " is performing computations!");
testVariable = testVariable - 50;
testVariable = testVariable / 2;
testVariable = testVariable * 33;
System.out.println(me.getName() + " modified the value to : "
+ testVariable + "\n");
sleep(2000);
mySharedData.releaseLock();
} catch (InterruptedException e) {
System.err.println("Failed to get lock when reading:" + e);
}
} else {
try {
sleep(2000);
mySharedData.acquireLock();
System.out.println(me.getName()
+ " is performing computations!");
testVariable = testVariable * 20;
testVariable = testVariable / 10;
testVariable = testVariable - 1;
System.out.println(me.getName() + " modified the value to : "
+ testVariable + "\n");
sleep(2000);
mySharedData.releaseLock();
} catch (InterruptedException e) {
System.err.println("Failed to get lock when reading:" + e);
}
}
System.out.println("The final result of the variable is "
+ testVariable);
}
}
The threads are executed in another class with its own main thread of execution:
public class SharingExample {
public static void main(String[] args) {
SharedData mySharedData = new SharedData();
SharedDataThread myThread1 = new SharedDataThread("myThread1", mySharedData);
SharedDataThread myThread2 = new SharedDataThread("myThread2", mySharedData);
SharedDataThread myThread3 = new SharedDataThread("myThread3", mySharedData);
SharedDataThread myThread4 = new SharedDataThread("myThread4", mySharedData);
// Now start the threads executing
myThread1.start();
myThread2.start();
myThread3.start();
myThread4.start();
}
}
the SharedData class is just a class for implementing locks and such.
public class SharedData {
private boolean accessing=false; // true a thread has a lock, false otherwise
private int threadsWaiting=0; // number of waiting writers
// attempt to acquire a lock
public synchronized void acquireLock() throws InterruptedException{
Thread me = Thread.currentThread(); // get a ref to the current thread
System.out.println(me.getName()+" is attempting to acquire a lock!");
++threadsWaiting;
while (accessing) { // while someone else is accessing or threadsWaiting > 0
System.out.println(me.getName()+" waiting to get a lock as someone else is accessing...");
//wait for the lock to be released - see releaseLock() below
wait();
}
// nobody has got a lock so get one
--threadsWaiting;
accessing = true;
System.out.println(me.getName()+" got a lock!");
}
// Releases a lock to when a thread is finished
public synchronized void releaseLock() {
//release the lock and tell everyone
accessing = false;
notifyAll();
Thread me = Thread.currentThread(); // get a ref to the current thread
System.out.println(me.getName()+" released a lock!");
}
}
Where is the problem here?
Your 'testVariable' should be marked as 'volatile'. See this topic for more information: Volatile Vs Static in java.