понеділок, 26 січня 2015 р.

String comparison in java

Comparison is the second common operation with strings in java. Let's find out which of this four functions are faster than other:

1. String.intern()
2. String.equals()
3. String.equalsIgnoreCase()
4. String.compareTo()

I decide to use in my benchmark array of 1000 random strings and compare elements from first path (0..499) with elements from second path (500..999):

  @Setup
    public void prepare() {
        testStringsPool = new String[1000];
        for (int i = 0; i < testStringsPool.length; i++) {
            int customLength = rnd.nextInt();
            if (customLength < 0) {
                customLength *= -1;
            }
            testStringsPool[i] = randomString(customLength % 20 + 10);
        }
    }

Here are my benchmark functions without annotations:

    public void intern_() {
        for (int i = 0; i < testStringsPool.length / 2; i++) {
            if (testStringsPool[i].intern() ==
                testStringsPool[testStringsPool.length - i – 1].intern());
        }
    }

    public void equals_() {
        for (int i = 0; i < testStringsPool.length / 2; i++) {
            if (testStringsPool[i].equals(
                testStringsPool[testStringsPool.length - i – 1]));
        }
    }

    public void compareTo_() {
        for (int i = 0; i < testStringsPool.length / 2; i++) {
            if (testStringsPool[i].compareTo(
                   testStringsPool[testStringsPool.length - i - 1]) == 0);
        }
    }

    public void equalsIgnoreCase_() {
        for (int i = 0; i < testStringsPool.length / 2; i++) {
            If(testStringsPool[i].equalsIgnoreCase(
                 testStringsPool[testStringsPool.length - i - 1]));
        }
    }

When we run those benchmark tests, we get something similar like this:

# Run complete. Total time: 00:00:25

Benchmark                                    Mode  Samples    Score   Error  Units
t.StringOpts.compareTo_                avgt        1          0.270 ±   NaN  us/op
t.StringOpts.equalsIgnoreCase_    avgt        1          1.323 ±   NaN  us/op
t.StringOpts.equals_                       avgt        1          0.348 ±   NaN  us/op
t.StringOpts.intern_                        avgt        1       148.612 ±   NaN  us/op


The winner is String.compareTo function

Conclusion for string comparison:

1. compareTo – is the fastest because it operates with parameter of String class without additional checking for type safety
2. equals – a bit slower by checking input parameter for the same type (String)
3. equalsIgnoreCase – more slower because all the characters are converted to uppercase in both strings
4. intern – the slowest. But when you need to work with many identical strings it can help you to reduce memory usage.

понеділок, 19 січня 2015 р.

String concatenation in Java

What is the most commonly used class in java projects?

We use jmap tool from jdk to find the answer.

jmap -histo | head -n 14

Where - java application process id (I have used pid of running tomcat server)

The output of this command is:
num     #instances         #bytes  class name
----------------------------------------------
   1:         43101       18737736  [B
   2:         61736       10054912  [C
   3:         11598        5165024  [I
   4:         58901        1413624  java.lang.String
   5:          8514         749232  java.lang.reflect.Method
   6:         21313         682016  java.util.HashMap$Node
   7:          5286         549960  java.lang.Class
   8:          7914         483944  [Ljava.lang.Object;
   9:          9323         372920  java.util.HashMap$ValueIterator
  10:          1814         320184  [Ljava.util.HashMap$Node;
  11:          7862         314480  java.lang.ref.Finalizer


As we can see String is one of the common used classes in java projects and takes a lot of memory. The most common operations performed with strings is concatenation.

There are three variants of string concatenation:

1. String a = “Hello ” + “world”; 
2. String b = new StringBuffer();
    b.append(“Hello ”);
    b.append(“world”).toString(); 
3. String c = “Hello ”.concat(“world”);

Let's look to them closer and try to compare. There are two common possibilities to concatenate strings using '+' sign:

1. String s1 = “STRING_VAL1” + “STRING_VAL2”;

2. String s2 = “STRING_VAL1” + STRING_VARIABLE;

We need to view generated bytecode by javap from jdk to compare them:

javap -c SomeJava.class

For the first expression it looks like this. 

Source:
String q = "Hello " + "world";

Bytecode:
  public static void main(java.lang.String[]) throws java.lang.Exception;
    Code:
       0: ldc           #3                  // String Hello world
       2: astore_1
       3: return

For the second expression.

Source:
String hello = "Hello ";
String result = hello + "world";

Bytecode:
  public static void main(java.lang.String[]) throws java.lang.Exception;
    Code:
       0: ldc           #3                  // String Hello
       2: astore_1
       3: new           #4                  // class java/lang/StringBuilder
       6: dup
       7: invokespecial #5                  // Method java/lang/StringBuilder."":()V
      10: aload_1
      11: invokevirtual #6                  // Method java/lang/StringBuilder.append
      14: ldc           #7                  // String world
      16: invokevirtual #6                  // Method java/lang/StringBuilder.append
      19: invokevirtual #8                  // Method java/lang/StringBuilder.toString
      22: astore_2
      23: return 

If you try to concatenate two or more constant strings then java compiler do this operation in compile time:

String s = “Hello ” + “world” + “...”;

In other cases will be used explicitly or implicitly StringBuilder and String.concat() method. StringBuffer is also possible for multithreading applications, but we examine only first two in bold. Let's decide which of them better


We will create two microbenchmark tests to find out which is better StringBuilder or String.concat:

@State(Scope.Thread)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class StringOpts {
    @Benchmark
    @BenchmarkMode({Mode.AverageTime})
    @OutputTimeUnit(TimeUnit.MICROSECONDS)
    public void concat_() {
        String s1 = "Hello";
        String s2 = s1.concat(" world");
    }

    @Benchmark
    @BenchmarkMode({Mode.AverageTime})
    @OutputTimeUnit(TimeUnit.MICROSECONDS)
    public void append_() {
        StringBuilder s1 = new StringBuilder("Hello");
        String s2 = s1.append(" world").toString();
    }
}

When benchmark had been finished we got such result:

# Run complete. Total time: 00:00:12

Benchmark               Mode  Samples  Score   Error  Units
t.StringOpts.append_    avgt        1  0.007 ±   NaN  us/op
t.StringOpts.concat_    avgt        1  0.010 ±   NaN  us/op

Where you can see that StringBuilder.append is faster than String.concat function. When you need concatenate only two strings in some cases you can prefer String.concat because this generates less objects than when you use StringBuilder.


субота, 3 січня 2015 р.

JMS (from my old report)

You can see original slides in http://www.slideshare.net/mybbslides/jms-14767911


General concepts


Queues


Topics


Message types

JMS specification provides standard implementations of javax.jms.Message:
1. javax.jms.BytesMessage - array of bytes
2. javax.jms.MapMessage - key-value pairs
3. javax.jms.ObjectMessage - serialized Java object
4. javax.jms.StreamMessage - stream of Java primitive values
5. javax.jms.TextMessage - Java String object (used for XML)

JMS working algorithm

1. Obtain a javax.jms.ConnectionFactory using JNDI lookup. (ConnectionFactory
names are different depending on JMS provider.)
2. Obtain a javax.jms.Connection from the ConnectionFactory.
3. Obtain a javax.jms.Session from the Connection.
4. Create a javax.jms.MessageProducer or javax.jms.MessageConsumer from the Session.
5. Send a message for the MessageProducer, or receive a message for the MessageConsumer
(synchronous) or set a message listener (asynchronous).
6. Start the Connection to start message delivery.
7. Finally close the Connection.

Synchronous messaging

while(true) {
    Message message = consumer.receive();
    ....
}

Asynchronous messaging (listener class)

class AsyncConsumerMessageListener implements MessageListener {
    public void onMessage(Message message) {
        TextMessage msg = (TextMessage) message;
        ....
    }
}

Asynchronous messaging (listener class usage)

AsyncConsumerMessageListener asyncConsumer = new AsyncConsumerMessageListener();
MessageConsumer consumer = session.createConsumer(destination);
consumer.setMessageListener(asyncConsumer);

Spring amqConnectionFactory

<bean class="org.apache.activemq.ActiveMQConnectionFactory" id="amqConnectionFactory">
    <property name="brokerURL" value="${jms.url}"/>
</bean>


1) jms.url=tcp://localhost:61616
2) jms.url=vm://localhost

Spring jmsQueueConnectionFactory

<bean id="jmsQueueConnectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory">
    <property name="targetConnectionFactory" ref="amqConnectionFactory"/>
</bean>

Spring listener-container

<jms:listener-container connection-factory="jmsQueueConnectionFactory" destination-type="queue" container-type="default">
    <jms:listener destination="TESTQUEUE" method="onMessage" ref="webConsumer"/>
</jms:listener-container>

Spring jmsTemplate

<bean class="org.springframework.jms.core.JmsTemplate" id="jmsTemplate">
    <constructor-arg ref="jmsQueueConnectionFactory"/>
</bean>

Spring message listener

@Component
public class WebConsumer implements MessageListener
{
    public void onMessage( final Message message ) {...}
}

Spring producer

@Component
public class WebProducer
{
    @Autowired
    private JmsTemplate jmsTemplate;

    public void send(String message) throws JMSException
    {
        jmsTemplate.convertAndSend("TESTQUEUE", message);
    }
}

Sources and useful links

1. Official JMS tutorial book
2. http://www.thirdeyeconsulting.com/indyjug/jms/jms.html
3. http://www2.sys-con.com/itsg/virtualcd/Java/archives/0604/chappell/index.html