400 likes | 541 Views
Chapter 8. Three Interfaces: Cloneable , Serializable , and Runnable. Cloning objects. To clone an object is to make an exact copy of it. A cloned object should be independent of the source object from which it is cloned.
E N D
Chapter 8 Three Interfaces: Cloneable, Serializable, and Runnable
Cloning objects • To clone an object is to make an exact copy of it. • A cloned object should be independent of the source object from which it is cloned. • An object is cloned by invoking its method clone(), which has protected scope in Object.
Cloning basics • To enable cloning, a class declares the clone() method inherited ultimately from Object as public. In Object, the method is protected. • A public override of the inherited clone() method should throw a CloneNoteSupportedException.
Cloning basics • If a class’s fields include object or array references, the clone() override must ensure that, after the cloning, the source and target objects are independent. • Object’s method clone()simply copies references so that a clone source and target wind up with references to the same object.
Cloning basics • Arrays can be cloned. A cloned array has the same number of elements and the same contents as the source array. • Cloning can be disabled by having a public override of clone()explicitly throw a CloneNotSupportedException.
Serialization basics • Serialization is the process of transforming an in-memory object to a byte stream. • Deserialization is the inverse process of reconstructing an object from a byte stream to the same state in which the object was previously serialized. • “Serializing out” and “serializing in” are also used.
Serialization basics • The requirements for serialization are straightforward: • Only class instances rather than primitive types can be serialized. • For an object to be serializable, its class or some ancestor must implement the emptySerializable interface. • An empty interface is called a markerinterface.
Serialization basics • The syntax for serialization is straightforward: • An object is serialized by writing it to an ObjectOutputStream. • An object is deserialized by reading it from an ObjectInputStream.
Serialization code FileOutputStream out = new FileOutputStream( “save.ser” ); ObjectOutputStream oos = new ObjectOutputStream( out ); oos.writeObject( new Date() ); oos.close();
Deserialization code FileInputStream in = new FileInputStream( “save.ser” ); ObjectInputStream ois = new ObjectInputStream( in ); Date d = (Date) ois.readObject(); ois.close();
Object graphs • If an object has references to other objects or arrays, the entire object graph is serialized when the object is serialized. • The object graph consists of the object directly serialized and any other objects or arrays to which the object has direct or indirect references.
Nonserializable superclasses • If a serializable class C has a nonserializable superclass S, instances of C still can be serialized if S has an accessible no-argument constructor. • S’s no-argument constructor is invoked automatically during deserialization to construct the “S-part” of the deserialized object.
Serialization and primitive types • Technically, primitive types cannot be serialized or deserialized. However, the ObjectOutputStream implements the DataOutput interface, which declares methods such as writeInt to write primitive types to streams. • ObjectInputStream implements DataInput for reading primitive types.
transient and static fields • A field marked as transient is not impacted by serialization. • During deserialization, transient fields are restored to their default values (e.g., transient numeric fields are restored to zero). • static fields are not impacted by serialization.
Customization • Serialization and deserialization can be customized by providing private callback methods named writeObject and readObject, respectively. • The Externalizable interface can be implemented by classes that need to have complete control over serialization and deserialization.
Cautionary notes • The same object should not be repeatedly serialized to the same stream. • A class should not be redefined in between the serialization and deserialization of its instances. • Classes that need to disable serialization can throw a NotSerializableException in the private callback writeObject.
Multithreading basics • A thread of control is a sequence of instructions that execute in the JVM. • Java programs begin as single-threaded programs but can become multithreaded by constructing and starting Threads. • A program can have arbitrarily many threads of execution.
Multithreading basics • A typical code segment to construct and start a thread is Thread t = new Thread( this ); t.start(); where this refers to a Runnable target. • A runnable target is an object whose class implements the Runnable interface.
Multithreading basics • The Runnable interface declares a single method public void run(); • The run() method is a pure callback; that is, the programmer defines but never invokes run(). • The system invokes run()to execute a thread; the programmer invokes start().
Multithreading basics • If Thread is extended, the subclass should override the inherited run(), which returns immediately. • The override of run() provides whatever code a thread should execute. • A thread stops permanently once it returns from run(). • A stopped thread cannot be restarted.
Thread priorities • If a program has multiple threads of the same priority executing, then thread execution is interleaved in unpredictable ways. • Threads have priorities ranging from MIN_PRIORITY through MAX_PRIORITY, which are numeric constants.
Thread priorities • Although the range for thread priorities is not standardized, typical values are • 1 for MIN_PRIORITY. • 5 for NORM_PRIORITY. • 10 for MAX_PRIORITY. • The JVM uses priority-based, preemptive scheduling: a higher priority thread always preempts a lower priority thread.
Thread priorities • If two threads T1 and T2 are started, but T2 has a higher priority than T1, then T2 preempts T1 if T1 is executing; and T1 does not execute again until T2 stops. • A thread of a given priority P starts another thread of the same priority. The setPrioritycan change a thread’s priority before the thread is started.
User and daemon threads • Threads are of two types: user threads and daemon threads. • A program continues to run so long as at least one user thread is alive. By contrast, a daemon thread by itself cannot sustain a program’s execution. • The garbage collector runs as a daemon thread.
User and daemon threads • A user thread constructs a user thread; a daemon thread constructs a daemon thread. • The setDaemon method can be invoked to change a thread’s daemon status before the thread is started. • Daemon threads are “helper” threads for user threads.
Thread states • A thread is one of four possible states: • Initial state. A newly constructed thread is in its initial state until started. • Runnable state. Once started, a thread is runnable or “alive” until the thread stops. • Blocked state. A thread can be blocked in various ways, e.g., by sleeping or waiting. A blocked thread becomes runnable once unblocked.
Thread states • Stop state. A thread enters the stop state if it returns from run() or the deprecated stop() method is invoked on it. • Once stopped, a thread cannot be restarted. • If a thread needs to run indefinitely, the run() method can have an infinite loop in it.
Thread groups • Every thread belongs to a ThreadGroup, which is either explicitly named or a default thread group. • Thread groups are a convenience. For instance, if several threads belong to a group, then setDaemon could be invoked on the group as a whole instead of on each individual thread.
Thread synchronization • Suppose that threads T1 and T2 read and write a shared field. In this case, T1 and T2 need to be synchronized so that, for example, T1 is not reading while T2 is writing. (Write operations are not “atomic” but rather consist of (a) evaluating the assignment value and (b) assigning the value to the target.)
Thread synchronization • Java provides a lock construct to ensure single-threaded execution of critical section code, that is, code to which threads must have mutually exclusive access. • The synchronized keyword can be used to lock a block of code within a method or an entire method.
Thread synchronization • The code segment synchronized( this ) { // single-threaded execution } shows the syntax of a synchronized block. The lock is the object to which this refers. • A synchronized block requires an object as a lock.
Thread synchronization • The code segment synchronized void getChopsticks() { //... single-threaded execution } shows the syntax for a synchronized method. The implicit lock is the object to which this refers.
Thread synchronization • A thread that gains a lock can invoke wait to release the lock until a subsequent invocation of notify or notifyAll by the thread that gains the lock. • Invocation of wait is guaranteed to be “atomic” or “noninterruptable.” • A thread that invokes wait simultaneously releases the lock and goes into a waiting state.
Thread synchronization • notify awakens an arbitrary waiting thread, whereas notifyAll awakens all waiting threads. • Either method can be invoked even if no threads happen to be waiting at the time. • The methods awaken only threads that went into a wait state beforehand. • The methods are typically invoked as the last statement in a synchronized block or method.
Deadlock • Synchronization locks open the possibility of deadlock, a condition that involves at least two threads. In deadlock, each thread holds a lock and releases it only when the other threads release their locks. • The JVM does not detect, prevent, or recover from deadlock. The programmer must avoid deadlock.
The join method • Suppose that t1 and t2 refer to two threads and that the t1-thread invokes t2.join(); // wait for t2 to stop The invocation causes the t1-thread to wait until the t2-thread stops. • The join method is a powerful construct for thread synchronization.
Deprecated thread methods • The stop method has been deprecated. The preferred way to stop a thread is to have the thread return from run(). • A stopped thread releases any held locks. • The suspend and resume methods have been deprecated because suspend is deadlock-prone and resume is used only in conjunction with suspend.
Critical section problems • Solutions to critical section problems are judged on four criteria. The synchronization mechanism in Java helps satisfy two of the four criteria.
Critical section problems • The four criteria are: • Progress. If a critical section is unlocked, a thread should be able to enter it. The synchronized construct ensures this behavior. • Mutual exclusion. At most one thread can hold a lock only a critical section. The synchronized construct ensures this behavior.
Critical section problems • Starvation. None of the threads trying to enter a critical section should be permanently prevented from doing so. The synchronized construct does not prevent starvation. • Fairness. Each of N contending threads should enter the critical section roughly the same amount of time. The synchronized construct does not ensure fairness.