How to Start Two Threads at "Exactly" the Same Time

How to start two threads at exactly the same time

To start the threads at exactly the same time (at least as good as possible), you can use a CyclicBarrier:

// We want to start just 2 threads at the same time, but let's control that 
// timing from the main thread. That's why we have 3 "parties" instead of 2.
final CyclicBarrier gate = new CyclicBarrier(3);

Thread t1 = new Thread(){
public void run(){
gate.await();
//do stuff
}};
Thread t2 = new Thread(){
public void run(){
gate.await();
//do stuff
}};

t1.start();
t2.start();

// At this point, t1 and t2 are blocking on the gate.
// Since we gave "3" as the argument, gate is not opened yet.
// Now if we block on the gate from the main thread, it will open
// and all threads will start to do stuff!

gate.await();
System.out.println("all threads started");

This doesn't have to be a CyclicBarrier, you could also use a CountDownLatch or even a lock.

This still can't make sure that they are started exactly at the same time on standard JVMs, but you can get pretty close. Getting pretty close is still useful when you do for example performance tests. E.g., if you are trying to measure throughput of a data structure with different number of threads hitting it, you want to use this kind of construct to get the most accurate result possible.

On other platforms, starting threads exactly can be a very valid requirement btw.

Ensure that two threads start at the same time

Turns out I have found a workaround that is doable without slowing the UI.
I just combined this two threads together in a single thread with a for loop

Final code looks like something like this.

std::thread timerTrial(&endTrial,this);
//....
void endTrial(){
int nbOfLogsNeeded = //Compute how many logs I will need during the time of trial
for(int i = 0 ; i < nbOfLogsNeeded ; i++){
std::this_thread::sleep_until(std::chrono::system_clock::now() + std::chrono::milliseconds(50));
//Perform Logging
}
}

It does not entirely answer the question but the workaround works just fine for me.

How to make multiple Threads run at the same time using a for loop in Java?

From the javadoc https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html :

class PrimeRun implements Runnable {
long minPrime;
PrimeRun(long minPrime) {
this.minPrime = minPrime;
}

public void run() {
// compute primes larger than minPrime
. . .
}
}

Your logic must be in the run() method. It's this method that will be called and run on another thread.
With your actual code, you do the calculation in the Runnable's constructor, which is called in your for loop, and therefor is sequential.

Moving your calculation to the run method will solve the problem.

edit: if you struggled to pass parameters to your computation code, you could have simplified to this :

Thread t1 = new Thread(() -> findPrimes(u, o, i));
t1.start();

It does exactly the same thing, under the hood, it creates an anonymous class that implement the Runnable interface that captures your variables in the class fields.

Java execute multiple Threads and wait for completion

You may use a CountDownLatch in addition to the barrier. Pass the CountDownLatch to each of the thread, once the firmware update is completed, just call the count-down on the latch. In your main thread, after starting all the threads, you may wait by calling latch.await and it will wail till all the other threads finish. You may find a sample here.

You can even use a CountDownLatch with 1 as the count for the starting gun in your case, which precludes the use of the CyclicBarrier.

Running two threads at the same time

Multi-threading and parallel processing are two completely different topics, each worthy of its own conversation, but for the sake of introduction...

Threading:

When you launch an executable, it is running in a thread within a process. When you launch another thread, call it thread 2, you now have 2 separately running execution chains (threads) within the same process. On a single core microprocessor (uP), it is possible to run multiple threads, but not in parallel. Although conceptually the threads are often said to run at the same time, they are actually running consecutively in time slices allocated and controlled by the operating system. These slices are interleaved with each other. So, the execution steps of thread 1 do not actually happen at the same time as the execution steps of thread 2. These behaviors generally extend to as many threads as you create, i.e. packets of execution chains all working within the same process and sharing time slices doled out by the operating system.

So, in your system call example, it really depends on what the system call is as to whether or not it would finish before allowing the execution steps of the other thread to proceed. Several factors play into what will happen: Is it a blocking call? Does one thread have more priority than the other. What is the duration of the time slices?

Links relevant to threading in C:

SO Example

POSIX

ANSI C

Parallel Processing:

When multi-threaded program execution occurs on a multiple core system (multiple uP, or multiple multi-core uP) threads can run concurrently, or in parallel as different threads may be split off to separate cores to share the workload. This is one example of parallel processing.

Again, conceptually, parallel processing and threading are thought to be similar in that they allow things to be done simultaneously. But that is concept only, they are really very different, in both target application and technique. Where threading is useful as a way to identify and split out an entire task within a process (eg, a TCP/IP server may launch a worker thread when a new connection is requested, then connects, and maintains that connection as long as it remains), parallel processing is typically used to send smaller components of the same task (eg. a complex set of computations that can be performed independently in separate locations) off to separate resources (cores, or uPs) to be completed simultaneously. This is where multiple core processors really make a difference. But parallel processing also takes advantage of multiple systems, popular in areas such as genetics and MMORPG gaming.

Links relevant to parallel processing in C:

OpenMP

More OpenMP (examples)

Gribble Labs - Introduction to OpenMP

CUDA Tookit from NVIDIA

Additional reading on the general topic of threading and architecture:

This summary of threading and architecture barely scratches the surface. There are many parts to the the topic. Books to address them would fill a small library, and there are thousands of links. Not surprisingly within the broader topic some concepts do not seem to follow reason. For example, it is not a given that simply having more cores will result in faster multi-threaded programs.

How to make two threads work in same time

You want an implementation of producer-consumer problem bro... Frankly speaking, without having a lock on the Object's monitor, you dont have control over anything. You dont have control over how much time a thread executes (Timeslice provided to it). If the time slice is too long, you will feel that one thread executes after another because your processor is so fast, your first thread will get ample time to finish its work . If you want to know how threads work exactly, use wait() and notify() and synchronized methods to change it into a producer-consumer problem.

  1. Jeanne is also right, you can put sleep() , there's a 90 percent chance that it might work.
  2. You could increase the number of elements being filled/printed.
  3. There's a 70% chance of you reading more than what you wrote(filled in the array) if you dont use syncronized/wait/notify.

Can two threads be assigned to different processors and execute at the same time?

You asked:

Can two threads be assigned to different processors and execute at the same time?

Yes.

A couple of threads may be sharing a processor core, with one running while the other waits. Modern CPUs often have hyper-threading technology to make this switching back and forth quite cheap (little overhead, fast performance). But at any one moment only a single thread can be running on a core.

A machine with a multi-core processor can be simultaneously running a different thread on each core. Two cores can be running two threads total, at any one moment. Three cores, three threads, and so on. The cores operate separately, each executing instructions on their own at the very same moment. As mentioned above, there may be additional threads assigned to a core, waiting its turn to execute.

You asked:

could the OS choose to execute two or more threads created by the same process (not the same thread, but different ones, like t1 and t2) at the same time?

Yes certainly. The host OS can choose to run any thread of any process at any time. For a process running Java, the JVM is also involved in scheduling the threads within its jurisdiction.

For the threads to be executing literally simultaneously, they would be assigned to separate CPU cores.

If two threads share a core, then they must wait to take turns as mentioned above. One thread is executing on the core while the other is not, back and forth. This rapid switching creates the illusion of running together at the same time, but that is not literally true. Hyper-threading technology makes this illusion so convincing that modern OSes such as macOS report hyper-threaded cores as multiple cores. For example, a 4-core Intel CPU with Hyper-Threading technology will be reported in the macOS Activity Monitor app (and top console command) as 8 cores even though technically only 4 threads are ever executing at any one moment. Indeed, there is some small overhead involved in switching threads even with hyper-threading, so some sysadmins may choose to disable hyper-threading on a machine that is dedicated to doing CPU-bound tasks. The example 8 virtual cores will be reduced to being only 4 real cores after disabling hyper-threading.

You asked:

If that's the case, can we ensure that it's happening?

No. Scheduling execution of threads is the business of the JVM and host OS, not us programmers writing Java code.

You asked:

I think I'm having some troubles understanding the scheduling that is being done,

We cannot understand the scheduling, because CPU core scheduling is controlled by the OS and JVM as mentioned above. So scheduling decisions are up to them. Those decisions will vary depending on the capabilities of the hardware, and on the current runtime conditions. The scheduling behavior may change with version updates to the host OS or the implementation of Java.

You asked:

because I thought that if a process creates a thread, the only processor that could be executing that task is the one that has the process being executed, but now I'm not that sure.

You may be thinking of processor affinity, also known as "CPU pinning". To quote Wikipedia:

Processor affinity … enables the binding and unbinding of a process or a thread to a central processing unit (CPU) or a range of CPUs, so that the process or thread will execute only on the designated CPU or CPUs rather than any CPU.

As far as I know, programmers writing Java code have no control over any processor affinity features your particular CPU architecture may offer. We do not know if our Java thread is staying with one core or is being moved around to different cores at different times. Not our business, except we need know the implications mentioned below.

The upshot is that we Java programmers do not control any aspect of the scheduling of threads’ execution.

If doing any threading, be sure to read the classic book Java Concurrency in Practice by Brian Goetz et al. And learn about the Java Memory Model and “visibility” issues, the volatile keyword, the Atomic… classes, and the executor framework. And keep your eyes peeled for advancements with Project Loom under development now.

Caveat: I am over-simplifying for clarity. If you care about the gory details, start with the Wikipedia pages I linked.

Code

Regarding your example code, understand that in modern Java we rarely need to address the Thread class directly. The executor framework was added to Java 5 to relieve us Java programmers from the chore of juggling thread management.

Write your task as either a class implementing Runnable, or as a lambda with a run method.

Here is some example code of running 100 tasks with 3 threads. Beware: The System.out console output is not in chronological order. If you care, study the timestamps.

System.out.println( "INFO - demo starting.  " + Instant.now() );

// Submit tasks to run on background threads.
ExecutorService executorService = Executors.newFixedThreadPool( 3 );
for ( int i = 0 ; i < 100 ; i++ )
{
executorService.submit( ( ) -> System.out.println( "Thread id " + Thread.currentThread().getId() + " is executing its task at " + Instant.now() ) );
}

// Wait for tasks to complete.
executorService.shutdown();
try { executorService.awaitTermination( 1 , TimeUnit.HOURS ); } catch ( InterruptedException e ) { e.printStackTrace(); }

System.out.println( "INFO - demo ending. " + Instant.now() );

When run.

INFO - demo starting.  2021-03-30T03:07:31.695531Z
Thread id 16 is executing its task at 2021-03-30T03:07:31.719603Z
Thread id 14 is executing its task at 2021-03-30T03:07:31.718036Z
Thread id 15 is executing its task at 2021-03-30T03:07:31.718036Z
Thread id 16 is executing its task at 2021-03-30T03:07:31.731698Z
Thread id 15 is executing its task at 2021-03-30T03:07:31.731745Z
Thread id 14 is executing its task at 2021-03-30T03:07:31.731772Z
Thread id 16 is executing its task at 2021-03-30T03:07:31.731762Z
Thread id 15 is executing its task at 2021-03-30T03:07:31.731809Z
Thread id 14 is executing its task at 2021-03-30T03:07:31.731836Z
Thread id 16 is executing its task at 2021-03-30T03:07:31.731867Z
Thread id 15 is executing its task at 2021-03-30T03:07:31.731888Z
Thread id 14 is executing its task at 2021-03-30T03:07:31.731910Z
Thread id 16 is executing its task at 2021-03-30T03:07:31.731934Z
Thread id 15 is executing its task at 2021-03-30T03:07:31.731955Z
Thread id 14 is executing its task at 2021-03-30T03:07:31.731978Z
Thread id 16 is executing its task at 2021-03-30T03:07:31.732001Z
Thread id 15 is executing its task at 2021-03-30T03:07:31.732028Z
Thread id 14 is executing its task at 2021-03-30T03:07:31.732046Z
Thread id 16 is executing its task at 2021-03-30T03:07:31.732065Z
Thread id 15 is executing its task at 2021-03-30T03:07:31.732088Z
Thread id 14 is executing its task at 2021-03-30T03:07:31.732109Z
Thread id 16 is executing its task at 2021-03-30T03:07:31.732127Z
Thread id 15 is executing its task at 2021-03-30T03:07:31.732141Z
Thread id 14 is executing its task at 2021-03-30T03:07:31.732160Z
Thread id 16 is executing its task at 2021-03-30T03:07:31.732185Z
Thread id 15 is executing its task at 2021-03-30T03:07:31.732207Z
Thread id 14 is executing its task at 2021-03-30T03:07:31.732229Z
Thread id 16 is executing its task at 2021-03-30T03:07:31.732250Z
Thread id 15 is executing its task at 2021-03-30T03:07:31.732271Z
Thread id 14 is executing its task at 2021-03-30T03:07:31.732293Z
Thread id 16 is executing its task at 2021-03-30T03:07:31.732320Z
Thread id 15 is executing its task at 2021-03-30T03:07:31.732340Z
Thread id 14 is executing its task at 2021-03-30T03:07:31.732359Z
Thread id 16 is executing its task at 2021-03-30T03:07:31.732374Z
Thread id 15 is executing its task at 2021-03-30T03:07:31.732391Z
Thread id 14 is executing its task at 2021-03-30T03:07:31.732408Z
Thread id 16 is executing its task at 2021-03-30T03:07:31.732424Z
Thread id 15 is executing its task at 2021-03-30T03:07:31.732440Z
Thread id 14 is executing its task at 2021-03-30T03:07:31.732464Z
Thread id 16 is executing its task at 2021-03-30T03:07:31.732484Z
Thread id 15 is executing its task at 2021-03-30T03:07:31.732501Z
Thread id 14 is executing its task at 2021-03-30T03:07:31.732516Z
Thread id 16 is executing its task at 2021-03-30T03:07:31.732535Z
Thread id 15 is executing its task at 2021-03-30T03:07:31.732556Z
Thread id 14 is executing its task at 2021-03-30T03:07:31.732579Z
Thread id 16 is executing its task at 2021-03-30T03:07:31.732598Z
Thread id 15 is executing its task at 2021-03-30T03:07:31.732617Z
Thread id 14 is executing its task at 2021-03-30T03:07:31.732632Z
Thread id 16 is executing its task at 2021-03-30T03:07:31.732648Z
Thread id 15 is executing its task at 2021-03-30T03:07:31.732669Z
Thread id 14 is executing its task at 2021-03-30T03:07:31.732684Z
Thread id 16 is executing its task at 2021-03-30T03:07:31.732698Z
Thread id 15 is executing its task at 2021-03-30T03:07:31.732718Z
Thread id 14 is executing its task at 2021-03-30T03:07:31.732735Z
Thread id 16 is executing its task at 2021-03-30T03:07:31.732753Z
Thread id 15 is executing its task at 2021-03-30T03:07:31.732770Z
Thread id 14 is executing its task at 2021-03-30T03:07:31.732785Z
Thread id 16 is executing its task at 2021-03-30T03:07:31.732805Z
Thread id 15 is executing its task at 2021-03-30T03:07:31.732819Z
Thread id 14 is executing its task at 2021-03-30T03:07:31.732834Z
Thread id 16 is executing its task at 2021-03-30T03:07:31.732858Z
Thread id 15 is executing its task at 2021-03-30T03:07:31.732878Z
Thread id 14 is executing its task at 2021-03-30T03:07:31.732896Z
Thread id 16 is executing its task at 2021-03-30T03:07:31.732910Z
Thread id 15 is executing its task at 2021-03-30T03:07:31.732936Z
Thread id 14 is executing its task at 2021-03-30T03:07:31.732955Z
Thread id 16 is executing its task at 2021-03-30T03:07:31.732970Z
Thread id 15 is executing its task at 2021-03-30T03:07:31.732985Z
Thread id 14 is executing its task at 2021-03-30T03:07:31.733011Z
Thread id 15 is executing its task at 2021-03-30T03:07:31.733056Z
Thread id 16 is executing its task at 2021-03-30T03:07:31.733034Z
Thread id 16 is executing its task at 2021-03-30T03:07:31.733168Z
Thread id 14 is executing its task at 2021-03-30T03:07:31.733106Z
Thread id 15 is executing its task at 2021-03-30T03:07:31.733123Z
Thread id 14 is executing its task at 2021-03-30T03:07:31.733279Z
Thread id 15 is executing its task at 2021-03-30T03:07:31.733311Z
Thread id 14 is executing its task at 2021-03-30T03:07:31.733335Z
Thread id 15 is executing its task at 2021-03-30T03:07:31.733371Z
Thread id 14 is executing its task at 2021-03-30T03:07:31.733386Z
Thread id 15 is executing its task at 2021-03-30T03:07:31.733425Z
Thread id 14 is executing its task at 2021-03-30T03:07:31.733469Z
Thread id 16 is executing its task at 2021-03-30T03:07:31.733221Z
Thread id 14 is executing its task at 2021-03-30T03:07:31.733535Z
Thread id 15 is executing its task at 2021-03-30T03:07:31.733485Z
Thread id 16 is executing its task at 2021-03-30T03:07:31.733582Z
Thread id 14 is executing its task at 2021-03-30T03:07:31.733605Z
Thread id 15 is executing its task at 2021-03-30T03:07:31.733643Z
Thread id 16 is executing its task at 2021-03-30T03:07:31.733659Z
Thread id 15 is executing its task at 2021-03-30T03:07:31.733700Z
Thread id 14 is executing its task at 2021-03-30T03:07:31.733680Z
Thread id 16 is executing its task at 2021-03-30T03:07:31.733736Z
Thread id 15 is executing its task at 2021-03-30T03:07:31.733754Z
Thread id 14 is executing its task at 2021-03-30T03:07:31.733779Z
Thread id 16 is executing its task at 2021-03-30T03:07:31.733798Z
Thread id 15 is executing its task at 2021-03-30T03:07:31.733818Z
Thread id 16 is executing its task at 2021-03-30T03:07:31.733848Z
Thread id 14 is executing its task at 2021-03-30T03:07:31.733833Z
Thread id 15 is executing its task at 2021-03-30T03:07:31.733880Z
Thread id 16 is executing its task at 2021-03-30T03:07:31.733900Z
Thread id 14 is executing its task at 2021-03-30T03:07:31.733918Z
INFO - demo ending. 2021-03-30T03:07:31.734044Z

If you want to collect results from your tasks, make them Callable rather than Runnable. And capture the Future object returned by the executor service on each call submitting your task. When all the tasks are done, loop the Future objects to ask for the result contained in each.



Related Topics



Leave a reply



Submit