views:

1055

answers:

14

On Paul Tyma's presentation, I found an interview question:

What's harder, synchronizing 2 threads or synchronizing 1000 threads?

From my perspective, of course synchronizing 1000 threads is harder, but I can't think of a good reasons for that beside 'of course'. But since it's interview question, may be I'm wrong (interview questions have to be tricky, isn't it?).

+3  A: 

Why would synchronizing 1000 threads be any harder than synchronizing 2 threads?

The only code that would be added would be to spawn the extra threads.

You wouldn't have to add any synchronization code (as long as you were doing everything correctly).

Justin Niessner
+14  A: 

Synchronizing a thousand threads is just as easy as synchronizing two threads: just lock access to all important data.

Now, synchronizing a thousand threads with good performance is more difficult. If I were asking this question, I'd look for answers mentioning "the thundering herd problem", "lock contention", "lock implementation scalability", "avoiding spinlocks", etc.

Borealid
A: 

it's equally hard. But synchronization over 2 threads will most likely perform better, since there are only 2 Threads concurring on one Lock instead of a thousand where there most likely be much more overhead due to locked resources.

Hope that helped

smeg4brains
+3  A: 

I think the answer is that after you have two threads synchronized all other 998 will also be synchronized

ZloiAdun
A: 

Objects are synchronized not threads. Creating a synchronized method or code block prevents multiple threads from executing the region at the same time - so it doesn't matter if there are 2, 1,000 or 1,000,000 threads.

In terms of performance, if you are expecting to double parallelism (half execution time) when you double the number of threads, then any synchronised region is going to be a bottle neck in terms of performance because it is essentially serial code which cannot be parallelised.

Tarski
why the downvote?
Tarski
Because threads are synchronized, not objects. Objects (or rather, the monitors attached to them) are the means by which this is achieved, but the goal is to coordinate ("synchronize") the threads that execute the code.
Michael Borgwardt
@Michael Borgwardt: It all depends what's meant by 'synchronized', though generally I would say ACTIONS are what need to be synchronized. Most actions involve a THREAD operating on some OBJECT. If two threads are doing totally independent things, there's no way to meaning fully "synchronize" them. While two related objects may be described as "in sync" or "out of sync" with each other, I don't think that's what the original question was talking about.
supercat
+1  A: 

It's one of those questions to which the only real answer is "it depends". In this case, it depends on what you're doing with them.

A scenario could be as simple as a single background worker thread that the foreground waits for while displaying a progress meter. Or it could spawn 1000 threads and simply wait for them all to finish before doing something else.

Alternatively, if as few as 2 threads are accessing shared resources, then the concepts are the same. You have to be very careful about concurrency issues and locking strategies whether it's 2 or 1000. Regardless of how many threads more than one, you can't guarantee that something else is not trying to simultaneously read or write to the same resource that you are.

Quick Joe Smith
+32  A: 

You could make the case that synchronizing 2 threads correctly is in fact harder than doing it for 1000, because if you have a race condition, it will usually manifest very quickly with 1000 threads, but not so with only 2.

But on the other hand, synchronizing 1000 threads without running into lock contention issues is much harder than when there are only 2.

The real answer is "synchronizing threads is hard in various ways, period."

Michael Borgwardt
+1 "if you have a race condition, it will usually manifest very quickly with 1000 threads, but not so with only 2." To me that is the key point - but maybe not the most obvious answer.
David Relihan
Well played, sir. Well played.
Justin K
A: 

If you use a programming language like Scala with a design pattern of Actors then you do not have to synchronize anything. http://www.scala-lang.org/node/242

Another option (in Java) is to go with a mechanism of compare and swap/set http://en.wikipedia.org/wiki/Compare-and-swap so you do not have to synchronize any threads in that they are atomic variable that you are comparing and reading through (non blocking) and only block/wait upon write which can get some huge performance gains based on your solution

Joe Stein
That's not completely true. I love Scala but there's still the issue of shared limited resources. That is, there can only be so many sockets, people writing to/read from a given file, etc.
wheaties
I really like Compare-And-Swap; I wonder why I don't see it pushed more. What was even more interesting was a 2-level conditional-load primitive I saw described in a white paper that should be practical to implement in hardware, and would allow for a practical double-compare-and-swap. DCAS allows for very practical lock-free data structures. Since I hate locks, I think a practical DCAS would be very useful.
supercat
+1  A: 

It depends what "is easier" means. The complexity of the design/locking mechanisms is roughly the same.

That being said, I think 1000 thread programs might be easier to debug. Vulnerable race-conditions have a higher probability of occurring and will probably be easier to replicate. A race condition in two threads might only appear once every 5 years if the moon is full and you're on vacation.

jdizzle
easier to replicate but harder to solve?
nanda
The hard part is figuring out that there it is a problem, what it is, and where it is. Being able to reliably replicate error conditions makes the problem much easier to solve.
jdizzle
+1  A: 

I would agree with those stating "it depends". If the threads are identical, then there moght not be such a big difference between 2 and 1000 threads. However, if there are multiple resources which need mutually exclusive access (synchronized in Java terms), then the likelihood of deadlocks may increase with the increasing number of threads.

Schedler
+3  A: 

I have two answers.

  1. CASE 1: Utilize existing resources: Synchronizing 2 threads is the same difficulty as synchronizing 1000 threads because existing are created for synchronizing an arbitrary number of threads.
  2. CASE 2: Implementing From Scratch It seems obvious that if you had to implement a synchronization system from scratch, then it would be easier to build the 2 thread system.
emory
I agree. With two threads, resource allocation is very simple; when a thread is done with a resource, THE other thread gets it. Starvation and priority inversion are non-issues. With three or more threads, some care is required to prevent starvation (a thread waiting endlessly for a resource that gets passed among other threads). If priorities are implemented, priority inversion can also be a problem (a max priority thread waiting on a resource held by a low-priority thread, while medium-priority threads hog the CPU). Those are non-issues with only two threads.
supercat
+1  A: 

Take reader-writer problem. With two threads, you can use mutual exclusion and it's done. With more threads, you have to write nontrivial code, since otherwise readers couldn't read simultaneously, or worse, they could starve the writers.

However, good synchronization code should work for any number of threads. In some cases, like mutual exclusion, you can add Java's synchronized keyword and it's as hard for 2 threads as for 1000.

In other words, if your program uses only 2 threads, you can take advantage of that and make assumptions that wouldn't be true with more threads. Obviously it's not a good practice, but it is possible.

sdcvvc
+2  A: 

In an interview, I would say that "exactly two threads" is a very useful special case of multi-threading. Things like starvation and priority inversion can occur with as few as three threads, but with only two threads priority inversion and starvation can never occur (well, starvation could occur if a thread released and reacquired a lock without letting the other thread start, but with three threads starvation can occur even if locks are grabbed instantly when available). Going from 2 threads to 3 is a bigger jump than going from 3 to 1,000.

supercat
+1  A: 

As I ran through your answers, I found several interesting toughts. I think, at the interview, this is more important than the answer: the conversion, the toughts.

ern0