Cross Column

Showing posts with label Java. Show all posts
Showing posts with label Java. Show all posts

Friday, February 14, 2014

java.lang.ClassCastException: [I cannot be cast to java.util.List.

Caused by: java.lang.ClassCastException: [I cannot be cast to java.util.List.
Initially, I was confused by seeing the sentence "I cannot be cast to..."  However, it turns out that it should be read as:
"[I" cannot be cast to "java.util.List"
In this article, we will look at the class name (i.e., "[I") used in the class file.

What Is "[I"?


"[I" means array of "ints."  If you use jrcmd to generate a heap histogram,[1] you will see the following contents:

--------- Detailed Heap Statistics: ---------
30.0% 65027k   672176     -1k [C
10.2% 22119k   943754     -2k java/lang/String
10.0% 21592k   183036     -3k [Ljava/lang/Object;
 4.7% 10185k   434587     +0k java/util/HashMap$Entry
 4.7% 10114k    27029  -1254k [B
 4.5% 9783k   111539     +0k [Ljava/util/HashMap$Entry;
 1.9% 4075k    34777     +0k java/lang/Class
 1.9% 4058k    86590     +0k java/util/HashMap
 1.6% 3448k   147156     +0k javax/management/ObjectName$Property
 1.2% 2593k    82994     +0k java/util/LinkedHashMap$Entry
 1.1% 2398k    76765     +0k java/util/concurrent/ConcurrentHashMap$Segment
 1.0% 2215k     9311     +0k [I
 0.9% 1975k    18469     +0k [J

Besides "[I", we also find other array's class names:
  • [C
  • [B
  • [J

Array Representation[2]



In Java, arrays are full-fledged objects. Like objects, arrays are always stored on the heap. Also, multi-dimensional arrays are represented as arrays of arrays.

Arrays have a Class instance associated with their class, just like any other object. All arrays of the same dimension and type have the same class. The length of an array (or the lengths of each dimension of a multidimensional array) does not play any role in establishing the array's class. For example, an array of three ints has the same class as an array of three hundred ints. The length of an array is considered part of its instance data.

The name of an array's class has one open square bracket for each dimension plus a letter or string representing the array's type. For example, the class name for an array of ints is "[I". The class name for a three-dimensional array of bytes is "[[[B". The class name for a two-dimensional array of Objects is "[[Ljava.lang.Object".  Read [3] for more details of this naming convention for array classes.

Conclusions


This exception
java.lang.ClassCastException: [I cannot be cast to java.util.List
turned out to be a bug in the application code, which applies a type cast as shown below:

while (iter.hasNext()) 
{ 
  key = iter.next(); 
  val = (List) mEDefToVOAttrsMap.get(key);  <=== this line threw the Exception

The object returned from get() method was created in this way:

iArr = new int[val.size()]; 

This bug was exposed when we switched from JDK 6 to 7 in our tests.  Maybe due to security enforcements or other reasons, JDK 7 provides more runtime checking than JDK 6 does.  Therefore, this hidden bug has been revealed.

To conclude:
The compiler is not backwards compatible[4] because bytecode generated with JDK 7 won't run in Java 1.6 VM (unless compiled with the -target 1.6 flag[5]). But the JVM is backwards compatible, as it can run older bytecodes.

References

  1. Diagnosing OutOfMemoryError or Memory Leaks in JRockit (Xml and More)
  2. Array Representation (The Java Virtual Machine)
  3. The class File Format
  4. Is JDK “upward” or “backward” compatible?
  5. Cross-Compilation Options
  6. Java Products: All About Versions (Xml and More)







Saturday, April 20, 2013

Analyze Hanging Programs Using Java Thread Traces

In this article, we will discuss the following topics:
  • How to analyze hanging, deadlocked or frozen programs?
  • How to generate stack traces?
  • What is deadlock?

What to Do When Your Applications Hang?


If you think your program is hanging, generate a stack trace.  A stack trace of all threads can be useful when trying to diagnose a number of issues such as deadlocks or hangs.

When looking at stack traces, check the following:
  • If a thread waits on
    • A monitor lock
    • A condition variable
  • If system threads show up as the current threads
    • If the program is deadlocked then some of the system threads will probably show up as the current threads, because there is nothing else for the JVM to do

How to Generate Stack Traces?


With thread stack trace, you can analyze the source of deadlocks.  There are multiple approaches:
  • Using jstack command, it can 
    • attach to the specified process (or core file) and prints the stack traces of all threads that are attached to the virtual machine (this includes Java threads and VM internal threads).
      • For each Java frame, the full class name, method name, 'bci' (byte code index) and line number, if available, are printed.
    • Obtain stack traces from a core dump:
      • jstack $JAVA_HOME/bin/java core
    • Be used to print a mixed stack.  That is, it can print native stack frames in addition to the java stack
      • Native frames are the C/C++ frames associated with VM code, and JNI/native code.
      • To print a mixed stack the -m option is used.
  • When a deadlock occurs, doing a Ctrl + Break on Windows forces a Java level thread stack trace to print to standard output. On Solaris and Linux, sending a SIGQUIT signal to the Java process id does the same.
  • Beginning with Java 6, the bundled JConsole tool added the capability to attach to a hung Java process and analyze the root cause of the deadlock.

What Is Deadlock?


If you're working with a moderately complex multithreaded program, then sooner or later, you'll hit the problem of deadlock[2,3].  Deadlock is the phenomenon when, typically, two threads each hold an exclusive lock that the other thread needs in order to continue.  In principle, there could actually be more threads and locks involved. Most of the time, a deadlock is caused by acquiring locks in the wrong order.

Deadlock can occur with any locking primitive. It notably occurs with the synchronized keyword, but it's liable to occur with locks, Semaphores, blocking queues etc.

A Deadlock Example


We used jstack to generate Java thread traces as follows:
$ jstack 3554

Our VM is HotSpot Client from JDK 7:

Found one Java-level deadlock:
=============================
"RunLevelControllerThread-1377458723460":
  waiting to lock monitor 0x871756a8 (object 0x93480480, a java.util.logging.LogManager$LoggerContext),
  which is held by "RunLevelControllerThread-1388458723457"
"RunLevelControllerThread-1388458723457":
  waiting to lock monitor 0x87173448 (object 0x93472290, a java.util.logging.LogManager),
  which is held by "RunLevelControllerThread-1377458723460"

Java stack information for the threads listed above:
===================================================
"RunLevelControllerThread-1377458723460":
    at java.util.logging.LogManager$LoggerContext.findLogger(LogManager.java:489)
    - waiting to lock <0x93480480> (a java.util.logging.LogManager$LoggerContext)
    at java.util.logging.LogManager.getLogger(LogManager.java:910)
    at com.sun.enterprise.server.logging.LogManagerService.postConstruct(LogManagerService.java:412)
    - locked < x93472290> (a java.util.logging.LogManager)
    - locked <0x93465158> (a java.lang.Class for java.util.logging.Logger)


"RunLevelControllerThread-1388458723457":
    at java.util.logging.LogManager.drainLoggerRefQueueBounded(LogManager.java:811)
    - waiting to lock <0x93472290> (a java.util.logging.LogManager)
    at java.util.logging.LogManager$LoggerContext.addLocalLogger(LogManager.java:511)
    - locked < x93480480> (a java.util.logging.LogManager$LoggerContext)

In the above example, you can see that two threads:

  • RunLevelControllerThread-1377458723460 
  • RunLevelControllerThread-1388458723457 

were waiting for locks that were held by each other.  This have created a deadlock.

References

  1. jstack - Stack Trace
  2. Deadlock
  3. How to Avoid Deadlocks (Xml and More)

Sunday, January 29, 2012

How to Avoid Deadlocks

Deadlock can be illustrated by the classic dining philosophers problem[1].

In an operating system, a deadlock[2] is a situation which occurs when a process enters a waiting state because a resource requested by it is being held by another waiting process, which in turn is waiting for another resource. If a process is unable to change its state indefinitely because the resources requested by it are being used by other waiting process, then the system is said to be in a deadlock.

In Java programming, deadlocks may manifest themselves where multiple threads wait forever due to a cyclic locking dependency.  For example, when thread A holds lock L and tries to acquire lock M, but at the same time thread B holds M and tries to acquire L, both threads will wait forever.  Just as threads can deadlock when they are each waiting for a lock that the other holds and will not release, they can also deadlock when waiting for resources. Comparing to deadlock, starvation and livelock are much less common a problem, but are still problems that every designer of concurrent software is likely to encounter. Java applications do not recover from deadlock, so it is worthwhile to ensure that your design precludes the conditions that could cause it[6].

In this article, we will discuss some threading best practices to avoid deadlocks.

Necessary Conditions

A deadlock situation can arise only if all of the following conditions hold simultaneously in a system:[3]
  1. Mutual Exclusion: At least, one resource must be non-shareable.  Only one process can use the resource at any given instant of time.
  2. Hold and Wait: A process is currently holding at least one resource and requesting additional resources which are being held by other processes.
  3. No Preemption: The operation system can de-allocate resources once they have been allocated. They must released by the holding process voluntarily.
  4. Circular Wait: A process waiting for a resource which is being held by another process, which in turn is waiting for another process to release a resource.
Unfulfillment of any of these conditions is enough to preclude a deadlock from occurring.

How to Avoid Deadlocks

Never cede control to the client within a synchronized method or block[4]

Invoking an alien method with a lock held is asking for liveness trouble. The alien method might acquire other locks (risking deadlock) or block for an unexpectedly long time, stalling other threads that need the lock you hold.

In other words, inside a synchronized region, do not invoke a method that is designed to be overridden, or one provided by a client in the form of a function object (i.e., object references used to implement the Strategy pattern).  The class has no knowledge of what the alien method does and has no control over it. If you do call an alien method from within a synchronized region, you open the opportunities of deadlocks by allowing the following conditions to hold:
  • Hold and Wait
  • Circular Wait
Because you call the alien method from a shynchronized region, it holds a lock. If this alien method is overriden and it engages the services of another thread to do the deed,  Hold and Wait condition will be established.  Given another counterpart of Hold-and-Wait, it can possibly form a Circular Wait condition.

Calling a method with no locks held is called an open call[6], and classes that rely on open calls are more well-behaved and composable than classes that make calls with locks held.

More generally, try to limit the amount of work that you do from within synchronized regions. When you are designing a mutable class, think about whether it should do its own synchronization. Synchronize your class internally only if there is a good reason to do so, and document your decision clearly.

Ensure that resources are always acquired in some well-defined order[7]

Deadlocks can be avoided by assigning a partial order to the resources, and establishing the convention that all resources will be requested in order, and released in reverse order, and that no two resources unrelated by order will ever be used by a single unit of work at the same time.  This solution to the dining philosophers problem was originally proposed by Dijkstra.

There are different approaches to enforce a partial order to the resources:
  1. If resources are static and known in advanced
    • Just stick to a programming policy (i.e., all programmers apply the policy of acquiring the locks in some well-defined order)
    • Provide a method that combines acquisition and release of the multiple locks in the correct way (see here for an example)
  2. If resources are not known in advanced or acquired dynamically
    • We have to explicitly define some way of ordering them. For example,
      • If locking will only exist for the lifetime of the application
        • We can use the identity hash code (System.identityHashCode(r)) of the two objects.
        • In the rare case that two objects have the same hash code, we must use an arbitrary means of ordering the lock acquisitions, and this reintroduces the possibility of deadlock. To prevent inconsistent lock ordering in this case, a third tie breaking lock can be used[6].
Removing the mutual exclusion condition

Removing the mutual exclusion condition means that no process will have exclusive access to a resource. This proves impossible for resources that cannot be spooled. But even with spooled resources, deadlock could still occur. Algorithms that avoid mutual exclusion are called non-blocking synchronization algorithms.

For example, optimistic concurrency control[9] uses a pair of consistency markers in the data structure. Processes reading the data structure first read one consistency marker, then read the relevant data into an internal buffer, then read the other marker, and then compare the markers. The data is consistent if the two markers are identical. Markers may be non-identical when the read is interrupted by another process updating the data structure. In such a case, the process discards the data in the internal buffer and tries again.

Finally, immutability is great for multi-threading. Instances of immutable class appear constant. Therefore, no external synchronization is necessary. Examples include String, Long, and BigInteger.

Using timed lock acquisition to acquire multiple locks[6]

Another technique for detecting and recovering from deadlocks is to use the timed tryLock feature of the explicit Lock classes instead of intrinsic locking.

If a lock acquisition times out, you can release the locks, back off and wait for a while, and try again, possibly clearing the deadlock condition and allowing the program to recover. However, this technique works only when the two locks are acquired together; if multiple locks are acquired due to the nesting of method calls, you cannot just release the outer lock, even if you know you hold it.

Conclusion

We conclude this article by quoting Goetz et al.[6]:
Like many other concurrency hazards, deadlocks rarely manifest themselves immediately. The fact that a class has a potential deadlock doesn’t mean that it ever will deadlock, just that it can. When deadlocks do manifest themselves, it is often at the worst possible time—under heavy production load.
References
  1. Dining philosophers problem
  2. Deadlock
  3. Advanced Synchronization in Java Threads by Scott Oaks and Henry Wong
  4. Effective Java by Joshua Block
  5. Threading Best Practices
  6. Java Concurrency in Practice by Brian Goetz, Tim Peierls, Joshua Bloch, Joseph Bowbeer, David Holmes and Doug Lea
  7. Deadlock Tutorial
  8. The Java Tutorial (Concurrency)
  9. Optimistic concurrency control
  10. Concurrency: State Models & Java Programs (2nd Edition), by Jeff Magee and Jeff Kramer.
  11. Java Concurrent Animated
  12. Analyze Hanging Programs Using Java Thread Traces (Xml and More)

Sunday, January 22, 2012

Volatile Keyword in Java

Multithreading is one of the most important software technologies for boosting the performance and scalability of all types of software.   However, it comes at a prisecomplexity.  The pain of concurrent programming can be alleviated by a framework like Hadoop.  However, as a Java programmer using threads, you need to deal with three interwined issues:
  1. Atomicity
  2. Visibility
  3. Ordering
Working Memory

Java Memory Model defines an abstract relation between threads and main memory. Every thread is defined to have a working memory (an abstraction of caches and registers) in which to store values. The model guarantees a few properties surrounding the interactions of instruction sequences corresponding to methods and memory cells corresponding to fields. Most rules are phrased in terms of when values must be transferred between the main memory and per-thread working memory.

Common variables such as instance fields, static fields and array elements in heap memory can be shared between threads.  At any time, these variables can be kept in one of the following locations:
  • Register
  • L1-L3 caches
  • Main memory
  • Hard disk (passivation and activation of Java Beans; paging or swapping)
When multiple threads are all running unsynchronized code that reads and writes common variables, then:
  • Arbitrary interleavings
  • Atomicity failures
  • Race conditions
  • Visibility failures
may result in execution patterns.
 
Atomicity

The language specification guarantees that reading or writing a single variable is atomic unless the variable is of type long or double.  This includes fields serving as references to other objects.  In other words, this implies that every thread accessing a field of any type except long or double will read its current value before continuing, instead of (potentially) using a cached value. This atomicity guarantee can be extended to longs or doubles, if you declare them volatile.  We'll discuss this more later.

Visibility

Visibility discusses under what conditions the effects of one thread are visible to another. The effects of interest here are writes to fields, as seen via reads of those fields.  While the atomicity guarantee ensures that a thread will not see a random value when reading atomic data, it does not gurantee that a value written by one thread will be visible to another:
  • Synchronization is required for reliable communication between threads as well as for mutual exclusion[8]
If a variable is declared volatile, this signals that the variable will be accessed by multiple threads, and also gives visibility guarantees.

Ordering

Ordering describes under what conditions the effects of operations can appear out of order to any given thread. The main ordering issues surround reads and writes associated with sequences of assignment statements.

If a program has no data races, then all executions of the program will appear to be sequentially consistent.  If JLS were to use sequential consistency as its memory model, many of the compiler and processor optimizations would be illegal.  For example, JLS allows the following statements to be reordered:


This provides essential flexibility for compilers and machines. Exploitation of such opportunities (via pipelined superscalar CPUs, multilevel caches, load/store balancing, interprocedural register allocation, and so on) is responsible for a significant amount of the massive improvements in execution speed seen in computing over the past decade.

In other words, not only may concurrent executions be interleaved, but they may also be reordered and otherwise manipulated in an optimized form that bears little resemblance to their source code. As compiler and run-time technology matures and multiprocessors become more prevalent, such phenomena become more common. They can lead to surprising results for programmers with backgrounds in sequential programming who have never been exposed to the underlying execution properties of allegedly sequential code. This can be the source of subtle concurrent programming errors. In almost all cases, there is an obvious, simple way to avoid contemplation of all the complexities arising in concurrent programs due to optimized execution mechanics: Use synchronization. There are multiple ways to achieve synchronization.  Below we'll disucusss using volatile keyword in Java for limited cases.

Volatile

In terms of atomicity, visibility, and ordering, declaring a field as volatile is nearly identical in effect to using a little fully synchronized class protecting only that field via get/set methods, as in:
final class VFloat { 
  private float value; 

  final synchronized void set(float f) { value = f; } 
  final synchronized float get() { return value; } 
}

This may invovle low-level memory barrier machine instructions to keep value representations in synch across threads.  However, it involves no locking.   In the following sections, we will discuss what're the good occasions for you to use volatile and what're the dangers of misusing it.

When to Use Volatile

Declaring fields as volatile can be useful when you do not need locking for any other reason, yet values must be accurately accessible across multiple threads. This may occur when[5]:
  • The field need not obey any invariants with respect to others.
  • Writes to the field do not depend on its current value.
  • No thread ever writes an illegal value with respect to intended semantics.
  • The actions of readers do not depend on values of other non-volatile fields.
Below we provide some examples for such usages:

Use volatile in DCL

Double-checked locking (DCL) is OK as of Java 5 provided that you make the instance reference volatile.

// Works with acquire/release semantics for volatile in Java 5
class Foo {
  private volatile Helper helper = null;
  public Helper getHelper() {
  if (helper == null) {
    synchronized(this) {
      if (helper == null)
        helper = new Helper();
      }
    }
    return helper;
  }
}

In Java 5, JLS ensures that the unsycnrhonized volatile read must happen after the write has taken place, and the reading thread will see the correct values of all fields on Helper.

Use volatile in Control Flag

// Cooperative thread termination with a volatile field
public class StopThread {
    private static volatile boolean stopRequested;

    public static void main(String[] args)
            throws InterruptedException {
        Thread backgroundThread = new Thread(new Runnable() {
            public void run() {
                int i = 0;
                while (!stopRequested)
                    i++;
            }
        });
        backgroundThread.start();

        TimeUnit.SECONDS.sleep(1);
        stopRequested = true;
    }
}

Volatile declarations on control flags are needed to ensure that result flag values are visible across threads.
  
Dangers of Using volatile Keyword

Composite operations such as the "++" operation on volatile variables both read and write the variable.  So, they are not atomic.

// Need to add synchronized modifier to the volatile variable
// Once you’ve done that, you can and should remove the volatile modifier 
// from nextSeuqenceNumber[8].
private static int nextSequenceNubmer = 0;
public static synchronized int nextSeuqenceNumber() {
  return nextSequenceNumber++;
}

Ordering and visibility effects surround only the single access or update to the volatile field itself. Declaring a reference field as volatile does not ensure visibility of non-volatile fields that are accessed via this reference. Similarly, declaring an array field as volatile does not ensure visibility of its elements.   In other words, it is unsafe to call arr[x] = y on an array (even if declared volatile) in one thread and then expect arr[x] to return y from another thread.  See [1] for possible ways of fixing this issue.

Because no locking is involved, declaring fields as volatile is likely to be cheaper than using synchronization, or at least no more expensive. However, if volatile fields are accessed frequently inside methods, their use is likely to lead to slower performance than would locking the entire methods.

References
  1. Volatile Arrays in Java
  2. Dangers of Volatile Keyword
  3. The Volatile Keyword in Java 5
  4. The Volatile Keyword in Java
  5. Synchronization and Thread Safety in Java
  6. Double-Checked Locking and How to Fix it
  7. Synchronization and Java Memory Model
  8. Effective Java by Joshua Bloch
  9. The Java Language Specification

© Travel for Life Guide. All Rights Reserved.

Analytical Insights on Health, Culture, and Security.