Java ThreadsDefinitionsProblemsWhy bother with concurrency?ThreadsThread poolsMutable and immutable objectsThe synchronized statement in Javasynchronized methods in JavaSynchronizing in ScalaLocksAtomic actionsData invariantsCheck-then-actSynchronization is on an objectLocal variablesThread deathsCommunication between ThreadsUse existing toolsAdviceDebuggingThe EndJan 14, 2019Java ThreadsFine grained, shared state2DefinitionsParallel processes—two or more Threads are running simultaneously, on different cores (processors), in the same computerConcurrent processes—two or more Threads are running asynchronously, on different cores (processors), in the same computerAsynchronous means that you cannot tell whether operation A in Thread #1 happens before, during, or after operation B in Thread #2Asynchronous processes may be running simultaneously, on different cores, or they may be sharing time on the same core23ProblemsConcurrency can lead to data corruption:Race conditions—if two or more processes try to write to the same data space, or one tries to write and one tries to read, it is indeterminate which happens firstConcurrency can lead to “freezing up” and other flow problems:Deadlock—two or more processes are each waiting for data from the other, or are waiting for the other to finishLivelock—two or more processes each repeatedly change state in an attempt to avoid deadlock, but in so doing continue to block one anotherStarvation—a process never gets an opportunity to run, possibly because other processes have higher priority34Why bother with concurrency?We use concurrency to make programs “faster”“Faster” may mean more responsiveWe need threads, even on single core machines, to move slow operations out of the GUI“Faster” may mean the computation completes soonerWe can:Break a computation into separate partsDistribute these partial computations to several coresCollect the partial results into a single resultThread creation, communication between threads, and thread disposal constitutes overhead, which is not present in the sequential versionDue to overhead costs, it is not unusual for first attempts at using concurrency to result in a slower programReally getting much speedup requires lots of experimentation, timing tests, and tuning the codeGood performance is not platform independent5ThreadsThere are two ways to create a Thread:Define a class that extends ThreadSupply a public void run() methodCreate an object o of that classTell the object to start: o.start();Define a class that implements Runnable (hence it is free to extend some other class)Supply a public void run() methodCreate an object o of that classCreate a Thread that “knows” o: Thread t = new Thread(o);Tell the Thread to start: t.start();56Thread poolsA thread pool is a collection of resuable threadsThis can save a lot of the overhead of creating and disposing of threadsVery basic introduction (Java 5+):import java.util.concurrent.*;...ExecutorService exec = Executors.newFixedThreadPool(20);Create some Runnable objects (objects that implement public void run() )exec.execute(Some Runnable object)7Mutable and immutable objectsIf an object is immutable (cannot be changed), then any number of Threads may read this object (or different portions of this object) at any timeSun provides a number of immutable objectsYou can create an ad hoc immutable object by simply not providing any way to change itAll fields must be final (private may not be enough)No methods may change any of the object’s dataYou must ensure no access to the object until after it is completely constructedIf an object is mutable (can be changed), and accessible by more than one Thread, then every access (write or read) to it must be synchronizedDon’t try to find clever reasons to think you can avoid synchronization78The synchronized statement in JavaSynchronization is a way of providing exclusive access to dataYou can synchronize on any Object, of any typeIf two Threads try to execute code that is synchronized on the same object, only one of them can execute at a time; the other has to waitsynchronized (someObject) { /* some code */ }This works whether the two Threads try to execute the same block of code, or different blocks of code that synchronize on the same objectOften, the object you synchronize on bears some relationship to the data you wish to manipulate, but this is not at all necessaryFundamental rule: If a mutable data item can be accessed by more than one thread, then every access to it, everywhere, must be synchronized. No exceptions!89synchronized methods in JavaInstance methods can be synchronized:synchronized public void myMethod( /* arguments */) { /* some statements */}This is equivalent topublic void myMethod( /* arguments */) { synchronized(this) { /* some statements */ }}Static methods can also be synchronizedThey are synchronized on the class object (a built-in object that represents the class)910Synchronizing in ScalaSame concepts, slightly different syntaxTo synchronize on an object:myObject.synchronized { // code block}To synchronize a method:def myMethod = synchronized { // code block}11LocksWhen a Thread enters a synchronized code block, it gets a lock on the monitor (the Object that is used for synchronization)The Thread can then enter other code blocks that are synchronized on the same ObjectThat is, if the Thread already holds the lock on a particular Object, it can use any code also synchronized on that ObjectA Thread may hold a lock on many different ObjectsOne way deadlock can occur is whenThread A holds a lock that Thread B wants, andThread B holds a lock that Thread A wants12Atomic actionsAn operation, or block of code, is atomic if it happens “all at once,” that is, no other Thread can access the same data while the operation is being performedx++; looks atomic, but at the machine level, it’s actually three separate operations:1. load x into a register2. add 1 to the register3. store the register back in xSuppose you are maintaining a stack as an array: void push(Object item) { this.top = this.top + 1; this.array[this.top] = item; }1. You need to synchronize this method, and every other access to the stack, to make the push operation
View Full Document