Win a copy of The Little Book of Impediments (e-book only) this week in the Agile and Other Processes forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

Javini Multi Threading Tools 01

 
Javini Javono
Ranch Hand
Posts: 286
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi,
The following are test classes I've been working with.
While there is no guarantee that you can with brute
force discover any multi-threading logic errors, it's
possible you may find the following rough drafts
of some interest.
Select the text and create the appropriate .java
files. Multi is the main class to run the test:
javac multi2/*.java
java multi2/Multi
If you have hints as to better ways to explore errors
in multi-threaded logic, please let me know.
Thanks,
Javini Javono
P.S.
The following listings were purposefully not
placed within code-brackets, because then the
line feed at the end of each line gets lost.

//***********************************
//The following are individual source files
//***********************************
//***********************************
//File multi2/Multi.java
//***********************************
package multi2;
import java.util.*;
public class Multi extends Object implements Runnable {

private static final boolean TRACK_INSTANTIATIONS = true;
private static intnumberOfInstancesCreatedToDate = 0;
private static boolean moreThanOneInstanceAllowed = true;

private static intnumberOfCompletedThreads = 0;

private SharedResource sharedResource = new SharedResource();

private booleanuseSyncObject = false;

private ObjectsyncObjectForMethodA = new Object();

private MultiAccountantmethodAMultiAccountant;

private static synchronized void trackClassInstantiations() {
if (TRACK_INSTANTIATIONS) {
numberOfInstancesCreatedToDate++;
if (!moreThanOneInstanceAllowed) {
if (numberOfInstancesCreatedToDate > 1) {
System.out.println("Multi.trackClassInstantiations(): Only one instance allowed, but numberOfInstancesCreatedToDate = " + numberOfInstancesCreatedToDate + "; this is a programmer logic error, exiting using System.exit(1).");
System.exit(1);
}
}
System.out.println("Multi.trackClassInstantiations(): numberOfInstancesCreatedToDate = " + numberOfInstancesCreatedToDate);
}
}

public Multi() {
trackClassInstantiations();
}

public int getValue() {
return sharedResource.getValue();
}

public void methodAMultiSetup() {

boolean designedForMultipleThreads = true;
boolean sendMultipleThreads = true;
boolean doBusyWork = false;
boolean doBusyWorkWithSleepNotCode = true;
boolean doBusyWorkOnlyWithYield = true;

try {
methodAMultiAccountant = new MultiAccountant("Multi[" + numberOfInstancesCreatedToDate + "].methodA()",
designedForMultipleThreads,
sendMultipleThreads,
doBusyWork,
doBusyWorkWithSleepNotCode,
doBusyWorkOnlyWithYield);
} catch (Exception tried) {
tried.printStackTrace();
}
}

private void methodA() {

if (methodAMultiAccountant != null) methodAMultiAccountant.entryLog();

try {
if (methodAMultiAccountant != null) methodAMultiAccountant.doBusyWork();

sharedResource.increment();
} catch (Exception tried) {
tried.printStackTrace();
}

if (methodAMultiAccountant != null) methodAMultiAccountant.exitLog();
}

private void runMultiProcessing() {
methodA();
}

private static synchronized void bumpNumberOfCompletedThreads() {
numberOfCompletedThreads++;
}

public void run() {
try {
if (useSyncObject) {
synchronized (syncObjectForMethodA) {
runMultiProcessing();
}
} else {
runMultiProcessing();
}
} catch (Exception tried) {
tried.printStackTrace();
} finally {
bumpNumberOfCompletedThreads();
}
}

public static void main(String[] args) {

intmax = 100; //10, 100, 1000, 10000, 100000
Multi multi = null;
Thread[] threads = new Thread[max];

try {
multi = new Multi();
multi.methodAMultiSetup();

for (int i = 0; i < max; i++) {
if (true) {
threads[i] = new Thread(multi);
} else {
//Example of not multi-threading against one object instance.
//So, don't do this usually if your intention is to multi-thread
//one instance.
multi = new Multi();
multi.methodAMultiSetup();
threads[i] = new Thread(multi);
}
}

for (int i = 0; i < max; i++) {
threads[i].start();
if (false) {
//Example of one way to force single threading.
threads[i].join();
}
}

while (numberOfCompletedThreads != max) {
Thread.sleep(1000);
}
System.out.println("Multi.main(): shared resource's value = " + multi.getValue());
if (max != multi.getValue()) {
System.out.println("Multi.main(): MULTI-THREADED LOGIC ERROR: multi.getValue() should be " + max);
}
} catch (Exception tried) {
tried.printStackTrace();
}
}
}
//***********************************
//File multi2/MultiAccountant.java
//***********************************
package multi2;
import java.util.*;
/*
Use one MultiAccountant for each multithreaded instance method.
*/
public class MultiAccountant extends Object {

private intnumberOfThreads = 0;
private intmaxNumberOfThreads = 0;

private StringmethodName;
private booleandesignedForMultipleThreads;
private booleansendMultipleThreads;
private booleandoBusyWork;
private booleandoBusyWorkWithSleepNotCode;
private booleandoBusyWorkOnlyWithYield;

private final intMULTIPLIER = 100;
private final intMAX_BUSY_WORK_VALUE = 10 * MULTIPLIER;
private final intMIN_BUSY_WORK_VALUE = 1 * MULTIPLIER;

private intmaxBusyWork = MAX_BUSY_WORK_VALUE;

private static boolean rising = false;

private ArrayList arrayList;

public MultiAccountant(String methodName,
boolean designedForMultipleThreads,
boolean sendMultipleThreads, //Not implemented; this input parameter is ignored.
boolean doBusyWork,
boolean doBusyWorkWithSleepNotCode,
boolean doBusyWorkOnlyWithYield) {

this.methodName = methodName;
this.designedForMultipleThreads = designedForMultipleThreads;
this.sendMultipleThreads = sendMultipleThreads;
this.doBusyWork = doBusyWork;
this.doBusyWorkWithSleepNotCode = doBusyWorkWithSleepNotCode;
this.doBusyWorkOnlyWithYield = doBusyWorkOnlyWithYield;
}

public synchronized void entryLog() {
numberOfThreads++;
}

public synchronized void exitLog() {
if (numberOfThreads > maxNumberOfThreads) {
maxNumberOfThreads = numberOfThreads;
System.out.println("MultiAccountant.exitLog(): for " + methodName + ": maxNumberOfThreads = " + maxNumberOfThreads);
if (!designedForMultipleThreads) {
if (numberOfThreads > 1) {
System.out.println("MultiAccountant.exitLog(): for " + methodName + ": maxNumberOfThreads = " + maxNumberOfThreads + ", but method was not designed to be multi-threaded; now calling System.exit() to halt program.");
System.exit(1);
}
}
}
numberOfThreads--;
}

private void decrementMaxBusyWork() {

if (maxBusyWork > MIN_BUSY_WORK_VALUE) {
maxBusyWork--;
}
}

private ArrayList doPrivateBusyWork() {

Stringa = "a";
Stringb = "b";
Stringc = "";

ArrayListarrayList = new ArrayList();

try {
intmax = 0;

if (doBusyWorkWithSleepNotCode) {
new RandomDelay().delay();
} else {
decrementMaxBusyWork();
max = maxBusyWork;

for (int i = 0; i < max; i++) {
if (i % 2 == 0) {
c = (new String("a") + new String("a") + new String("b")).substring(0, 1);
} else {
c = (new String("a") + new String("b") + new String("b")).substring(0, 1);
}
}
arrayList.add(c);
}
} catch (Exception tried) {
tried.printStackTrace();
}

return arrayList;
}

public void doBusyWork() {

if (doBusyWork) {
if (doBusyWorkOnlyWithYield) {
Thread.yield();
} else {
doPrivateBusyWork();
}
} else {
//Do nothing.
}
}
}
//***********************************
//File multi2/SharedResource.java
//***********************************
package multi2;
public class SharedResource extends Object {

private static final boolean TRACK_INSTANTIATIONS = true;
private static intnumberOfInstancesCreatedToDate = 0;
private static boolean moreThanOneInstanceAllowed = false;

private intsubValue1 = 0;
private intsubValue2 = 0;
private intvalue = 0;

private int[] intArray = new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

private static synchronized void trackClassInstantiations() {
if (TRACK_INSTANTIATIONS) {
numberOfInstancesCreatedToDate++;
if (!moreThanOneInstanceAllowed) {
if (numberOfInstancesCreatedToDate > 1) {
System.out.println("SharedResource.trackClassInstantiations(): Only one instance allowed, but numberOfInstancesCreatedToDate = " + numberOfInstancesCreatedToDate + "; this is a programmer logic error, exiting using System.exit(1).");
System.exit(1);
}
}
System.out.println("SharedResource.trackClassInstantiations(): numberOfInstancesCreatedToDate = " + numberOfInstancesCreatedToDate);
}
}

public SharedResource() {
trackClassInstantiations();
}

//On my computer, I could not force a multi-threaded logic error
//nomatter how many threads came through here, and nomatter how
//many calls to yield() I did; thus, I had to make value a compound
//result of subValue1 and subValue2.
//
//This relates to shared resources that write a record to a file.
//What you might do is this (though I haven't tried it yet myself):
//Normal test processing: yeild, write the complete record to the file;
//but, if this doesn't produce multi-threading
//errors, then try the next step.
//Extra Test processing: yield, write the first half of the record,
//yield, then write the second half of the record.

public int increment() {

try {
if (false) {
if (false) {
Thread.yield();
value++;
} else {
Thread.yield();
value = value + 1;
}
} else {
//On my computer, at leat one, well placed Thread.yield() was
//critical to getting this code to function illogically within
//a multi-threaded context.

for (int i = 0; i < intArray.length; i++) {
Thread.yield();
subValue1 = subValue1 + intArray[i];
}
for (int i = 0; i < intArray.length; i++) {
//Thread.yield();
subValue1 = subValue1 - intArray[i];
}
for (int i = 0; i < intArray.length; i++) {
//Thread.yield();
subValue2 = subValue2 + intArray[i];
}
for (int i = 0; i < intArray.length; i++) {
//Thread.yield();
subValue2 = subValue2 - intArray[i];
}
//Thread.yield();
value = (value + 1 + subValue1) - subValue2;
}
} catch (Exception tried) {
tried.printStackTrace();
}

return value;
}

public int getValue() {
return value;
}
}
//***********************************
//File multi2/RandomDelay.java
//***********************************
package multi2;
public class RandomDelay extends Object {

public void delay() {

int milliseconds = 0;

try {
boolean branch = false;
intiBranch = 0;

iBranch = (int) (Math.random() * 1000);
if (iBranch % 2 == 0) {
branch = true;
} else {
branch = false;
}

if (branch) {
milliseconds = (int) (Math.random() * 10);
if (milliseconds % 2 == 0) {
milliseconds = 1;
} else {
milliseconds = 2;
}
Thread.sleep(milliseconds);
} else {
milliseconds = (int) (Math.random() * 10);
Thread.sleep(milliseconds);
}
} catch (Exception tried) {
tried.printStackTrace();
}
}
}
[ February 08, 2004: Message edited by: Javini Javono ]
 
Javini Javono
Ranch Hand
Posts: 286
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi,
Here is the code within code-brackets for easier on-line
reading. However, if you want to copy the code and
compile and run it, then copy the code from the initial
posting above (though leading tabs have vanished from
the code):

[Andrew: tried to reformat code so that no horizontal scrolling is required]
[ February 08, 2004: Message edited by: Andrew Monkhouse ]
 
Andrew Monkhouse
author and jackaroo
Marshal Commander
Pie
Posts: 12014
220
C++ Firefox Browser IntelliJ IDE Java Mac Oracle
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Javini,
Thanks for posting this code - it could be useful to others.
I strongly recommend you read the Sun Code Conventions for the Java Programming Language.
I spent a fair bit of time reformatting your code so that it can fit in my browser without horizontal scrolling (and I am reading this on a 21" monitor with small fonts so I am not sure whether others will be able to read without scrolling). Generally I do not read posts where I have to scroll both horizontally and vertically.
If I have time later, I will come back and look at your code itself to see what you are doing.
Regards, Andrew
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic