So as the title suggests I am trying to find all the primes from 0 to MAX_LIMIT
sample input: javac Main.java 8 100
this means create 8 threads and find primes from 0 to 100, including 100.
my program takes two command line arguments: the first is the number of threads, the second is the range of primes (0 to n).
sample output:
Prime Number: 2 Thread #: 13
Prime Number: 7 Thread #: 15
Prime Number: 7 Thread #: 16
Prime Number: 11 Thread #: 18
:
Then the system will hang and ill have to stop the process:
Process finished with exit code 137
My question is:
Why does my thread pool go over its limit (thread numbers like 13 or 16, instead of 1-8)
and how can I make the threads not all calculate the same number at the same time?
I'm thinking of using a cache of some sort like adding numbers to an array list or something
but I do not know if that would be the correct approach to use.
It is possible that I am misunderstanding what a ThreadPool is and am in fact using something completely unrelated to it.
I am also unsure of why it is hanging and not printing all the primes from 0 to 100 in this case.
If there is an easier way to do what I am trying to do I would be interested in hearing it.
I'll be here working on this and will check back on this thread frequently.
Yes this is homework for an operating systems class about threads, I wouldn't normally ask for help but I am at a loss. All Code is located in one file.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
private static int MAX_THREADS;
private static int MAX_LIMIT;
private static int numToTest = 0;
public static void main(String[] args) {
int max_threads = Integer.parseInt(args[0]);
int max_limit = Integer.parseInt(args[1]);
MAX_THREADS = max_threads;
MAX_LIMIT = max_limit;
Foo();
}
private static void Foo() {
class PrimeNumberGen implements Runnable {
int num = numToTest;
PrimeNumberGen(int n) {num = n;}
boolean isPrime(int n) { //first test is 0
if(n<2) return false;
if(n==2) return true;
if(n%2==0) return false;
int max = n/2;
for(int i=3; i< max; i=i+2) {
if (n % i == 0)
return false;
}
return true;
}
public void run() {
numToTest++;
if(isPrime(num)) {
System.out.println("Prime Number: "+num+" Thread #:
"+Thread.currentThread().getId());
}
else {
numToTest++;
}
}
}
//Thread t = new Thread(new PrimeNumberGen(num));
//t.start();
ExecutorService executor = Executors.newFixedThreadPool(MAX_THREADS);
for (int i = 0;i <= MAX_LIMIT; i++) {
Runnable worker = new PrimeNumberGen(numToTest);
executor.execute(worker);
}
}
}
Your Thread id is a unique number of a thread. This can start at any number and doesn't have to be sequential. Over the life of a thread pool you can have more than the maximum number of threads, but no more than the maximum at any time.
BTW If you have to find multiple primes, using a Sieve of Eratosthenes will be much faster as it is a lower time complexity. It is usually single threaded, but it will still be faster.
Regarding the second part of your question, take a look at the Sieve of Eratosthenes.
Change
Runnable worker = new PrimeNumberGen(numToTest); to
Runnable worker = new PrimeNumberGen(i);
You can actually throw away this numToTest variable it's not needed anymore.
The problem for the duplicate prime numbers is that the threads do not see the updates of the other thread all the time, e.g.
Prime Number: 7 Thread #: 15
Prime Number: 7 Thread #: 16 (Thread 16 does not see the values from thread 15 perhaps they are running on different cores)
is because numToTest++; is not thread safe since numToTest is not volatile and the operation ++ is not atomic. I wrote a blog entry under http://blog.vmlens.com/2013/08/18/java-race-conditions-or-how-to-find-an-irreproducable-bug/ to explain this type of bug.
One solution would be to use AtomicInteger, see http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/atomic/AtomicInteger.html.
Your program seams to hang since you did not stop the thread pool. See How to stop the execution of Executor ThreadPool in java? how to do this.
Regarding the thread pool going over its limit,
Change
System.out.println("Prime Number: "+num+" Thread #:
"+Thread.currentThread().getId());
to
System.out.println("Prime Number: "+num+" Thread #:
"+Thread.currentThread().getName());
The thread ID is a positive long number generated when this thread was created, not the actual thread number; calling getName() will outputs something like
pool-1-thread-3
Ref : https://www.tutorialspoint.com/java/lang/thread_getid.htm
Related
I am learning multithreading. I have a following code:
public class Intro {
public static void main(String[] args) {
new Intro().doCounter();
}
private int counter = 0;
synchronized void increment() {
counter++;
}
private void doCounter() {
Thread thread1 = new Thread(new Runnable() {
#Override
public void run() {
for (int i = 0; i < 1_000_000; i++) {
increment();
}
System.out.println("first: " + counter);
}
});
Thread thread2 = new Thread(new Runnable() {
#Override
public void run() {
for (int i = 0; i < 1_000_000; i++) {
increment();
}
System.out.println("second: " + counter);
}
});
thread1.start();
thread2.start();
}
}
Output (can differ):
first: 1741739
second: 2000000
The code has two threads. One thread increment the counter million times, while the second wait. Then the second increment it million times as well. I understand why the second thread get 2 million, but didn't get why the first thread get 1741739. Why it isn't 1 million for the first thread? I think it had to stop at 1 million. Thanks for explanation.
As discussed in the comments, you have two problems.
You need to understand that threading execution is not predictable. Each thread gets scheduled for a certain amount of time on a CPU core as decided by the JVM and the OS. How often each thread gets scheduled, and for how long, depends on conditions at runtime. So their work can be interleaved, with no guarantee as to which thread will run when, or finish first/last.
Your code is accessing a resource, a member field variable counter across threads without protection. This is not thread-safe. Due to modern CPU architecture and the Java Memory Model, your two threads might see two different states of that single variable. For example, each of two cores running your two threads might each have a different copy of the variable in its cache.
One solution is to use AtomicInteger as your counter variable rather than int. An AtomicInteger is thread-safe, protecting access to its contained int value. By using AtomicInteger, you no longer need your synchronized increment method.
Here is some example code for that.
An Incrementor class that contains our AtomicInteger variable named count as a member field. The class carries nested class IncrementingTask that is a Runnable with a run method to be executed on background threads, incrementing our count var a million times. The class has a demo method for starting any number of threads, each thread running an instance of IncrementingTask to increment the million times.
package work.basil.threading;
import java.time.Instant;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class Incrementor
{
// Member fields.
final private AtomicInteger count = new AtomicInteger( 0 );
public void demo ( )
{
int threadsLimit = 2;
ExecutorService executorService = Executors.newFixedThreadPool( threadsLimit );
for ( int i = 0 ; i < threadsLimit ; i++ )
{
executorService.submit( new IncrementingTask() );
}
executorService.shutdown();
try { executorService.awaitTermination( 1 , TimeUnit.HOURS ); } catch ( InterruptedException e ) { e.printStackTrace(); }
// At this point, the tasks are all done/canceled/failed.
System.out.println( "RESULTS: count is at: " + this.count.get() );
}
// Runnable task.
class IncrementingTask implements Runnable
{
#Override
public void run ( )
{
for ( int i = 0 ; i < 1_000_000 ; i++ )
{
int incrementedCount = count.incrementAndGet();
if ( i % 100_000 == 0 )
{
System.out.println( "Thread # " + Thread.currentThread().getId() + " incremented count to: " + incrementedCount + " at " + Instant.now() );
}
}
System.out.println( "Thread # " + Thread.currentThread().getId() + " is done incrementing. " + Instant.now() );
}
}
}
A class to run this.
package work.basil.threading;
public class App
{
public static void main ( String[] args )
{
App app = new App();
app.demo();
}
private void demo ( )
{
Incrementor incrementor = new Incrementor();
incrementor.demo();
}
}
When run.
Thread # 15 incremented count to: 2 at 2021-03-29T00:04:37.099350Z
Thread # 14 incremented count to: 1 at 2021-03-29T00:04:37.099281Z
Thread # 14 incremented count to: 200002 at 2021-03-29T00:04:37.155680Z
Thread # 15 incremented count to: 198267 at 2021-03-29T00:04:37.155659Z
Thread # 15 incremented count to: 387108 at 2021-03-29T00:04:37.165850Z
Thread # 14 incremented count to: 400002 at 2021-03-29T00:04:37.165894Z
Thread # 15 incremented count to: 552150 at 2021-03-29T00:04:37.168378Z
Thread # 14 incremented count to: 631000 at 2021-03-29T00:04:37.169329Z
Thread # 15 incremented count to: 753457 at 2021-03-29T00:04:37.170931Z
Thread # 14 incremented count to: 840455 at 2021-03-29T00:04:37.171943Z
Thread # 15 incremented count to: 942263 at 2021-03-29T00:04:37.173276Z
Thread # 14 incremented count to: 1049089 at 2021-03-29T00:04:37.174559Z
Thread # 15 incremented count to: 1135900 at 2021-03-29T00:04:37.175726Z
Thread # 14 incremented count to: 1240800 at 2021-03-29T00:04:37.177092Z
Thread # 15 incremented count to: 1308191 at 2021-03-29T00:04:37.177678Z
Thread # 15 incremented count to: 1439696 at 2021-03-29T00:04:37.179523Z
Thread # 15 incremented count to: 1595283 at 2021-03-29T00:04:37.180795Z
Thread # 14 incremented count to: 1604140 at 2021-03-29T00:04:37.181720Z
Thread # 14 incremented count to: 1800001 at 2021-03-29T00:04:37.183231Z
Thread # 14 incremented count to: 1900001 at 2021-03-29T00:04:37.184697Z
Thread # 15 is done incrementing. 2021-03-29T00:04:37.182735Z
Thread # 14 is done incrementing. 2021-03-29T00:04:37.188265Z
RESULTS: count is at: 2000000
Notice that every time we run this, we always get to exactly 2,000,000 million total. Also notice that every time you run this, the list of which thread ran when will vary, as will the count at each time the thread reports to us on the console.
Console lies
Notice the counts look crazy. The first two lines report a count of 2 and then 1 rather than one then two. Same with the third and fourth lines, apparently backwards.
Look more closely to examine the microseconds of the timestamps. Those timestamps are not in chronological order.
Lesson learned: The System.out.println calls do not present on the console in chronological order. So never rely on such console output to give you a true picture of what happened when.
Always include a timestamp such as Instant.now() or System.nanoTime(). If you want to see messages in order, collect them in a thread-safe ordered collection such as Collections.synchronizedList​( new ArrayList< String >() ).
Alternatively, if you wanted to keep your int variable and synchronized increment method rather than use AtomicInteger you must protect access to the counter variable in a thread-safe manner. Marking the variable as volatile would help. You can search Stack Overflow to learn more on this.
public class Bank {
private int sum=0;
public void add(int n) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
sum+= n;
System.out.println(sum);
}
}
public class Consumer implements Runnable {
Bank bank = new Bank();
#Override
public void run() {
for (int i = 0; i < 10; i++) {
bank.add(100);
}
}
}
public class Tes2 {
public static void main(String[] args) {
Consumer consumer = new Consumer();
Thread thread1 = new Thread(consumer);
Thread thread2 = new Thread(consumer);
thread1.start();
thread2.start();
}
}
This is a multithreaded program, simulation is multiple depositors to the bank to deposit money, used to demonstrate multithreaded security issues.Since the code is not synchronized, its first and second results might be 200/200,200/300, and so on.But I don't understand why you get 100/100, who can explain?
This is a race condition.
Both threads have access to sum.
sum += n; is not atomic
Thread 1 reads sum 0
Thread 2 swaps in because the code isnt synchronized reads sum as 0
Thread 1 adds 100 to 0 and writes that to sum
Thread 2 adds 100 to 0 and writes that to sum overwriting thread 1s value
If you think about the concurrency of this program just based on the lines in the code, the 100/100 output result wouldn't make sense. But you also have to think about what instructions are actually happening when these lines are being performed. Each line of code can consist of many, many assembly instructions. In this case, to add n to sum, what really happens is that the value of sum is read from memory, probably loaded onto a register, incremented, then re-written onto memory.
The 100/100 output can happen in the following scenario. Let's say thread 1 and thread 2 both call bank.add(100), and the bank handles requests asynchronously. That is, the bank has a thread handling each request.
Then, thread 1 of the bank loads the value of sum, which is zero. Thread 2 also loads the value of sum right after, which is still zero. Then, thread 1 takes the value it loaded, adds n=100, and writes it into memory. Thread 2 does the same; it takes the value of sum it loaded previously, 0, adds 100, then writes it back onto memory. Then, they each print out the value of 100.
I achieved to calculate factorial with two threads without the pool. I have two factorial classes which are named Factorial1, Factorial2 and extends Thread class. Let's consider I want to calculate the value of !160000. In Factorial1's run() method I do the multiplication in a for loop from i=2 to i=80000 and in Factorial2's from i=80001 to 160000. After that, i return both values and multiply them in the main method. When I compare the execution time it's much better (which is 5000 milliseconds) than the non-thread calculation's time (15000 milliseconds) even with two threads.
Now I want to write clean and better code because I saw the efficiency of threads at factorial calculation but when I use a thread pool to calculate the factorial value, the parallel calculation always takes more time than the non-thread calculation (nearly 16000). My code pieces look like:
for(int i=2; i<= Calculate; i++)
{
myPool.execute(new Multiplication(result, i));
}
run() method which is in Multiplication class:
public void run()
{
s1.Mltply(s2); // s1 and s2 are instances of my Number class
// their fields holds BigInteger values
}
Mltply() method which is in Number class:
public void Multiply(int number)
{
area.lock(); // result is going wrong without lock
Number temp = new Number(number);
value = value.multiply(temp.value); // value is a BigInteger
area.unlock();
}
In my opinion this lock may kills the all advantage of the thread usage because it seems like all that threads do is multiplication but nothing else. But without it, i can't even calculate the true result. Let's say i want to calculate !10, so thread1 calculates the 10*9*8*7*6 and thread2 calculate the 5*4*3*2*1. Is that the way I'm looking for? Is it even possible with thread pool? Of course execution time must be less than the normal calculation...
I appreciate all your help and suggestion.
EDIT: - My own solution to the problem -
public class MyMultiplication implements Runnable
{
public static BigInteger subResult1;
public static BigInteger subResult2;
int thread1StopsAt;
int thread2StopsAt;
long threadId;
static boolean idIsSet=false;
public MyMultiplication(BigInteger n1, int n2) // First Thread
{
MyMultiplication.subResult1 = n1;
this.thread1StopsAt = n2/2;
thread2StopsAt = n2;
}
public MyMultiplication(int n2,BigInteger n1) // Second Thread
{
MyMultiplication.subResult2 = n1;
this.thread2StopsAt = n2;
thread1StopsAt = n2/2;
}
#Override
public void run()
{
if(idIsSet==false)
{
threadId = Thread.currentThread().getId();
idIsSet=true;
}
if(Thread.currentThread().getId() == threadId)
{
for(int i=2; i<=thread1StopsAt; i++)
{
subResult1 = subResult1.multiply(BigInteger.valueOf(i));
}
}
else
{
for(int i=thread1StopsAt+1; i<= thread2StopsAt; i++)
{
subResult2 = subResult2.multiply(BigInteger.valueOf(i));
}
}
}
}
public class JavaApplication3
{
public static void main(String[] args) throws InterruptedException
{
int calculate=160000;
long start = System.nanoTime();
BigInteger num = BigInteger.valueOf(1);
for (int i = 2; i <= calculate; i++)
{
num = num.multiply(BigInteger.valueOf(i));
}
long end = System.nanoTime();
double time = (end-start)/1000000.0;
System.out.println("Without threads: \t" +
String.format("%.2f",time) + " miliseconds");
System.out.println("without threads Result: " + num);
BigInteger num1 = BigInteger.valueOf(1);
BigInteger num2 = BigInteger.valueOf(1);
ExecutorService myPool = Executors.newFixedThreadPool(2);
start = System.nanoTime();
myPool.execute(new MyMultiplication(num1,calculate));
Thread.sleep(100);
myPool.execute(new MyMultiplication(calculate,num2));
myPool.shutdown();
while(!myPool.isTerminated()) {} // waiting threads to end
end = System.nanoTime();
time = (end-start)/1000000.0;
System.out.println("With threads: \t" +String.format("%.2f",time)
+ " miliseconds");
BigInteger result =
MyMultiplication.subResult1.
multiply(MyMultiplication.subResult2);
System.out.println("With threads Result: " + result);
System.out.println(MyMultiplication.subResult1);
System.out.println(MyMultiplication.subResult2);
}
}
input : !160000
Execution time without threads : 15000 milliseconds
Execution time with 2 threads : 4500 milliseconds
Thanks for ideas and suggestions.
You may calculate !160000 concurrently without using a lock by splitting 160000 into disjunct junks as you explaint by splitting it into 2..80000 and 80001..160000.
But you may achieve this by using the Java Stream API:
IntStream.rangeClosed(1, 160000).parallel()
.mapToObj(val -> BigInteger.valueOf(val))
.reduce(BigInteger.ONE, BigInteger::multiply);
It does exactly what you try to do. It splits the whole range into junks, establishes a thread pool and computes the partial results. Afterwards it joins the partial results into a single result.
So why do you bother doing it by yourself? Just practicing clean coding?
On my real 4 core machine computation in a for loop took 8 times longer than using a parallel stream.
Threads have to run independent to run fast. Many dependencies like locks, synchronized parts of your code or some system calls leads to sleeping threads which are waiting to access some resources.
In your case you should minimize the time a thread is inside the lock. Maybe I am wrong, but it seems like you create a thread for each number. So for 1.000! you spawn 1.000 Threads. All of them trying to get the lock on area and are not able to calculate anything, because one thread has become the lock and all other threads have to wait until the lock is unlocked again. So the threads are only running in serial which is as fast as your non-threaded example plus the extra time for locking and unlocking, thread management and so on. Oh, and because of cpu's context switching it gets even worse.
Your first attempt to splitt the factorial in two threads is the better one. Each thread can calculate its own result and only when they are done the threads have to communicate with each other. So they are independent most of the time.
Now you have to generalize this solution. To reduce context switching of the cpu you only want as many threads as your cpu has cores (maybe a little bit less because of your OS). Every thread gets a rang of numbers and calculates their product. After this it locks the overall result and adds its own result to it.
This should improve the performance of your problem.
Update: You ask for additional advice:
You said you have two classes Factorial1 and Factorial2. Probably they have their ranges hard codes. You only need one class which takes the range as constructor arguments. This class implements Runnable so it has a run-Method which multiplies all values in that range.
In you main-method you can do something like that:
int n = 160_000;
int threads = 2;
ExecutorService executor = Executors.newFixedThreadPool(threads);
for (int i = 0; i < threads; i++) {
int start = i * (n/threads) + 1;
int end = (i + 1) * (n/threads) + 1;
executor.execute(new Factorial(start, end));
}
executor.shutdown();
executor.awaitTermination(1, TimeUnit.DAYS);
Now you have calculated the result of each thread but not the overall result. This can be solved by a BigInteger which is visible to the Factorial-class (like a static BigInteger reuslt; in the same main class.) and a lock, too. In the run-method of Factorial you can calculate the overall result by locking the lock and calculation the result:
Main.lock.lock();
Main.result = Main.result.multiply(value);
Main.lock.unlock();
Some additional advice for the future: This isn't really clean because Factorial needs to have information about your main class, so it has a dependency to it. But ExecutorService returns a Future<T>-Object which can be used to receive the result of the thread. Using this Future-Object you don't need to use locks. But this needs some extra work, so just try to get this running for now ;-)
In addition to my Java Stream API solution here another solution which uses a self-managed thread-pool as you demanded:
public static final int CHUNK_SIZE = 10000;
public static BigInteger fac(int max) {
ExecutorService executor = newCachedThreadPool();
try {
return rangeClosed(0, (max - 1) / CHUNK_SIZE)
.mapToObj(val -> executor.submit(() -> prod(leftBound(val), rightBound(val, max))))
.map(future -> valueOf(future))
.reduce(BigInteger.ONE, BigInteger::multiply);
} finally {
executor.shutdown();
}
}
private static int leftBound(int chunkNo) {
return chunkNo * CHUNK_SIZE + 1;
}
private static int rightBound(int chunkNo, int max) {
return Math.min((chunkNo + 1) * CHUNK_SIZE, max);
}
private static BigInteger valueOf(Future<BigInteger> future) {
try {
return future.get();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static BigInteger prod(int min, int max) {
BigInteger res = BigInteger.valueOf(min);
for (int val = min + 1; val <= max; val++) {
res = res.multiply(BigInteger.valueOf(val));
}
return res;
}
I want to find out all the prime numbers from 0 to 1000000. For that I wrote this stupid method:
public static boolean isPrime(int n) {
for(int i = 2; i < n; i++) {
if (n % i == 0)
return false;
}
return true;
}
It's good for me and it doesn't need any edit. Than I wrote the following code:
private static ExecutorService executor = Executors.newFixedThreadPool(10);
private static AtomicInteger counter = new AtomicInteger(0);
private static AtomicInteger numbers = new AtomicInteger(0);
public static void main(String args[]) {
long start = System.currentTimeMillis();
while (numbers.get() < 1000000) {
final int number = numbers.getAndIncrement(); // (1) - fast
executor.submit(new Runnable() {
#Override
public void run() {
// int number = numbers.getAndIncrement(); // (2) - slow
if (Main.isPrime(number)) {
System.out.println("Ts: " + new Date().getTime() + " " + Thread.currentThread() + ": " + number + " is prime!");
counter.incrementAndGet();
}
}
});
}
executor.shutdown();
try {
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
System.out.println("Primes: " + counter);
System.out.println("Delay: " + (System.currentTimeMillis() - start));
} catch (Exception e) {
e.printStackTrace();
}
}
Please, pay attention to (1) and (2) marked rows. When (1) is enabled the program runs fast, but when (2) is enabled it works slower.
The output shows small portions with large delay
Ts: 1480489699692 Thread[pool-1-thread-9,5,main]: 350431 is prime!
Ts: 1480489699692 Thread[pool-1-thread-6,5,main]: 350411 is prime!
Ts: 1480489699692 Thread[pool-1-thread-4,5,main]: 350281 is prime!
Ts: 1480489699692 Thread[pool-1-thread-5,5,main]: 350257 is prime!
Ts: 1480489699693 Thread[pool-1-thread-7,5,main]: 350447 is prime!
Ts: 1480489711996 Thread[pool-1-thread-6,5,main]: 350503 is prime!
and threads get equal number value:
Ts: 1480489771083 Thread[pool-1-thread-8,5,main]: 384733 is prime!
Ts: 1480489712745 Thread[pool-1-thread-6,5,main]: 384733 is prime!
Please explain me why option (2) is more slowly and why threads get equal value for number despite AtomicInteger multithreading safe?
In the (2) case, up to 11 threads (the ten from the ExecutorService plus the main thread) are contending for access to the AtomicInteger, whereas in case (1) only the main thread accesses it. In fact, for case (1) you could use int instead of AtomicInteger.
The AtomicInteger class makes use of CAS registers. It does this by reading the value, doing the increment, and then swapping the value with the value in the register if it still has the same value that was originally read (compare and swap). If another thread has changed the value it retries by starting again : read - increment - compare-and-swap, until it is succesful.
The advantage is that this is lockless, and therefore potentially faster than using locks. But it performs poorly under heavy contention. More contention means more retries.
Edit
As #teppic points out, another problem makes case (2) slower than case (1). As the increment of numbers happens in the posted jobs, the loop condition remains true for much longer than needed. While all 10 threads of the executor are churning away to determine whether their given number is a prime, the main thread keeps posting new jobs to the executor. These new jobs don't get an opportunity to increment numbers until preceding jobs are done. So while they're on the queue numbers does not increase and the main thread can meanwhile complete one or more loops loop, posting new jobs. The end result is that many more jobs can be created and posted than the needed 1000000.
Your outer loop is:
while (numbers.get() < 1000000)
This allows you to continue submitting more Runnables than intended to the ExecutorService in the main thread.
You could try changing the loop to: for(int i=0; i < 1000000; i++)
(As others have mentioned you are obviously increasing the amount of contention, but I suspect the extra worker threads are a larger factor in the slowdown you are seeing.)
As for your second question, I'm pretty sure that it is against the contract of AtomicInteger for two child threads to see the same value of getAndIncrement. So something else must be going on which I am not seeing from your code sample. Might it be that you are seeing output from two separate runs of the program?
Explain me why option (2) is more slowly?
Simply because you do it inside run(). So multiple threads will try to do it at the same time hence there will be wait s and release s. Bowmore has given a low level explanation.
In (1) it is sequential. So there will be no such a scenario.
Why threads get equal value for number despite AtomicInteger
multithreading safe?
I don't see any possibility to happen this. If there's such a case it should happen from 0.
You miss two main points here: what AtomicInteger is for and how multithreading works in general.
Regarding why Option 2 is slower, #bowmore provided an excellent answer already.
Now regarding printing same number twice. AtomicInteger is like any other object. You launch your threads, and they check the value of this object. Since they compete with your main thread, that increases the counter, two child threads still may see same value. I would pass an int to each Runnable to avoid that.
I am beginner in programming and Java, and this is my first multi-core program. The problem is that my program never uses more than 13% of my CPU. I do not know if I do it in the right way or not.
How do I compute faster and use more CPU resources?
My program consists of three class:
The "main class that instantiates the Work object with a number of threads
A "T1" class that extends Thread and contains the work to be performed
A "Work" class that launches the desired thread numbers and displays the time taken by all threads to perform the work
Here is the code of my Main class:
public static void main(String[] args) {
System.out.println("Number of CPUs available = " + Runtime.getRuntime().availableProcessors()); //Display the number of CPUs available
int iteration = 100000000; // Define a number of itterations to do by all threads
/*
Instantiates each work with a different number of threads (1, 4, 8, 12, and 24)
*/
Work t1 = new Work(1);
Work t4 = new Work(4);
Work t8 = new Work(8);
Work t12 = new Work(12);
Work t24 = new Work(24);
/*
Launch the work for each thread with the specified number of iterations
*/
t1.goWork(iteration);
t4.goWork(iteration);
t8.goWork(iteration);
t12.goWork(iteration);
t24.goWork(iteration);
}
And here the Work class code:
public class Work {
static long time; // A variable that each thread increase by the time it takes to complete its task.
static int itterationPerThread; // A variable that stores the number of itterations Per Thread to do.
static int finish; // A variable that each thread incrase when it finish its task, used to wait until all thread has complete their task.
private int numberOfThreads; // The number of threads to launch.
/**
*
* The constructor, set the number Of threads to run
* #param numberOfThreads
*/
public Work(int numberOfThreads)
{
this.numberOfThreads = numberOfThreads; //Set the number of threads
}
/**
*
* A method that launch a specified number of thread in the constructor of the class, and distributes the a number of iteration of each thread.
* The method does nothing until each thread completes its task and print the time needed for all threads to complete their tasks.
* #param itterationPerThread
*/
public void goWork(int itterationPerThread)
{
finish = 0; //Reset the variable in the case that we call the method more than one time
time = 0; //Reset the variable in the case that we call the method more than one time
this.itterationPerThread = itterationPerThread/numberOfThreads; // Divide the given number of iterations by the number of threads specified in the constructor
for (int i=0; i<numberOfThreads; i++) //Launch the specified number of threads
{
new T1().run();
}
while (finish != numberOfThreads) //Do nothing until all thread as completed their task
{
}
System.out.println("Time for " + numberOfThreads + " thread = " + time + " ms"); //Display the total time
}
}
And finally my T1 class:
public class T1 extends Thread{
#Override
public void run()
{
long before = System.currentTimeMillis();
for (int i=0; i<Work.itterationPerThread; i++) //Get the thread busy with a number of itterations
{
Math.cos(2.1545); //Do something...
}
long after = System.currentTimeMillis(); //Compute the elapsed time
Work.time += after - before; //Increase the static variable in Work.java by the time elapsed for this thread
Work.finish++; // Increase the static variable in Work.java when the thread has finished its job
}
}
The programme gives me the following ouput on my machine (four physical cores and eight hyperthreaded):
Number of CPUs available = 8
Time for 1 thread = 11150 ms
Time for 4 thread = 4630 ms
Time for 8 thread = 2530 ms
Time for 12 thread = 2530 ms
Time for 24 thread = 2540 ms
According to my CPU this result seems correct, but my CPU usage never exceeds 13%.
I found the following Stack Overflow post, but I did not really find an answer to my question.
Instead of calling Thread.run(), which implements what your thread does, you should call Thread.start(), which will create a new thread and call run() on that new thread.
Now you are running run() on your main thread, without making a new thread. Since you have 13% CPU load, I expect you have 8 cores (meaning you have fully filled a single core).
Even better would be to create a custom implementation of the interface Runnable, instead of extending Thread. You can then run it on a thread as follows:
Thread t = new Thread(new MyRunnableTask());
t.start();
This is the common way because it gives you the flexibility (later on) to use more advanced mechanisms, such as ExecutorService.
EDIT:
As also noted in some of the comments. You are also changing the same variables (the static ones in Work) from several threads. You should never do this, because it allows for race conditions. For instance incrementing a variable can cause one, as explained here.
Thank you all for answering my question:
Yes, the JVM does not calculate the Math.cos(2.1545); on each iteration, so as said I've tried with Math.cos(i); on the original programme and there is a big difference!
And for the multi Thread, as said, I've created a custom implementation of the interface Runnable, instead of extending Thread and now use the Start(); method instead of run();
I now use the join method to wait until thread finish and remove the static variable.
Now the program use the full CPU load with the correct number of threads.
Just for information, here is my new code for the work class:
public class Work {
private Thread[] threadArray; //An array to store a specified number of new threads in the constructor
/**
*
* The constructor, set to the number Of threads to run
* #param numberOfThreads
*/
public Work(int numberOfThreads)
{
threadArray = new Thread[numberOfThreads];
}
/**
*
* A methode that launch a specified number of threads in the constructor of the class, and distributes the a number of iteration of each thread.
* the methode wait until each thread complete their task and print the time needed for all thread to complette their task.
* #param itterationForAllThread --> the total of itteration to do by all thread
*/
public void goWork(int itterationForAllThread)
{
long time = 0; // A variable used to compute the elapsed time
int itterationPerThread; // A variable that store the number of itterations Per Thread to do
itterationPerThread = itterationForAllThread/threadArray.length; //Divide the given number of itteration by the number of tread specified in the constructor
for(int i=0; i<threadArray.length; i++) //Launch the specified number of threads
{
threadArray[i] = new Thread(new T1(itterationPerThread)); //Create a new thread
threadArray[i].start(); //Start the job
}
long before = System.currentTimeMillis();
for (Thread thread : threadArray) //For each thread wait until it finish
{
try {
thread.join(); //Wait for the thread as finish
}
catch (InterruptedException ex)
{
ex.printStackTrace();
}
}
long after = System.currentTimeMillis();
time = after - before; //Compute the time elapsed
System.out.println("Time for " + threadArray.length + " Thread = " + time + " ms"); //Display the total time for the number of threads
}
}
And here the T1 class:
public class T1 implements Runnable{
private int iterrattionPerThread;
T1(int iterrattionPerThread)
{
this.iterrattionPerThread=iterrattionPerThread;
}
#Override
public void run()
{
for(int i=0; i<iterrattionPerThread; i++) //Get the thread busy with a number of iterations
{
Math.cos(i); //Do something that the JVM can not cache and need to be recaculated every iteration
}
}
}