Εμφάνιση αναρτήσεων με ετικέτα java. Εμφάνιση όλων των αναρτήσεων
Εμφάνιση αναρτήσεων με ετικέτα java. Εμφάνιση όλων των αναρτήσεων

Σάββατο 4 Φεβρουαρίου 2023

Project Valhalla Value objects and user-defined primitives



PROJECT VALHALLA: VALUE OBJECTS AND USER-DEFINED PRIMITIVES




THE PROBLEM

In a project there are classes that don't have any use for identity and their field values can be permanently set once on instantiation, and thus their instances don't need any synchronization and other OOP related optimizations.

However, by default they act like identity components and at runtime, the support for identity can be expensive. Particular memory location is required for object's data and extra metadata to support the object's functionalities.


PROJECT VALHALLA  

An alternative approach is to represent program data using primitive data types. As primitive values do not have a unique identity, they can be easily copied and efficiently stored as compact bit sequences. At the same time, we want to retain object-oriented semantics.

That said, the purpose here is to "augment the Java object model with value objects and user-defined primitives, combining the abstractions of OOP with the performance characteristics of primitives".



VALUE CLASSES


Value classes will be the bridge between the OOP benefits and primitives' performance.

With Valhalla, the JVM will try inlining value objects where possible. These value objects will be encoded directly   with its primitive field values, avoiding any overhead from object headers, indirections, or heap allocation.

As a non-goal of the related JEP, the Value classes will be reference types, stored in memory and can  be pointed to by multiple variables.


Structure:

   value class Shape {

     int x;

     int y;

   }

  ,where "value" dictates that the class and its fields would be Final, just like the regular VO objects.Value classes contain only primitives.


Being Final, they are immutable, and thus, lack identity:

In Java, final classes are unable to be altered after they have been created, making them immutable. This means that the values stored within their fields cannot be modified, and any attempts to do so will result in an error. This is why final classes lack identity, as their values cannot be changed, and thus their identity cannot be changed.

Subsequently we can compare Value class instances only by comparing all their field values. 


To summarize:

Value classes provide programmers with a mechanism to opt out of object identity, and in return get many of the performance benefits of primitive types, without giving up the other features of Java classes.

They cannot mutate, synchronize, and lack identity.

Value objects significantly improve object performance in many contexts, providing a good fusion of the better abstractions of objects with the better performance of primitives.


Value Classes drawbacks:

Value classes being the middle ground between objects and primitives, they present some drawbacks when used as fields or in arrays:

  • A variable of a Value type could be null, so we require additional bits to encode null.
  • As reference types, Value objects' variables must be modified atomically, so it not practical to inline Value objects.
Specifically, in an array with Value objects, there's still indirections and references to all elements that need memory usage:



This can be improved using Primitive classes, where possible:



PRIMITIVE CLASSES


A primitive class is a special kind of value class that introduces a new composite primitive type. Using class features, we can create a new primitive type containing other primitives. Primitive objects will be stored in stack as a unit, thus supporting a null-free flattened storage, and improved performance.

Contrary to Value classes, Primitive ones are more performant for arrays, as they have no references.They are stored directly in stack memory.

Structure:


Note the "primitive" keyword.

Primitive classes also have class methods to perform any calculations inside the object, ensuring encapsulation like in DDD design.

Primitive classes will come handy in the case of e.g. arrays, where their advantage over Value classes is the lack of indirections. In addition no null encoding needs exist, and atomic modification in also not needed as primitives stored in stack:

A memory layout of a Primitive array:



Primitive members are flattened memory-wise, and no extra pointers are needed.



CLASSES FOR THE BASIC PRIMITIVES


Project Valhalla is an initiative which seeks to migrate the Wrapper classes (java.lang.Integer, java.lang.Double, etc.) to become primitive classes. This is done in order to reduce the overhead of modeling primitive values with classes and offer the capabilities of class types for the basic primitives, with many details delegated to the standard library. Starting from Java 5, primitive values can be stored in the Wrapper classes and represented as objects, although there are drawbacks such as runtime costs and the potential for boxing identical values leading to two objects being unequal. JEP 401 outlines the improvements that will be made with the implementation of Project Valhalla.


ENHANCED GENERICS


To maintain the performance benefits of using primitives, existing frameworks and libraries have resorted to creating specializations such as IntStream<T> or ToIntFunction<T>. Currently, to use language primitives generically, we use boxed types, like Integer for int or Float for float, which introduces an extra layer of indirection and negates the purpose of using primitives. Enhanced generics is an effort to eliminate this workaround and allow generic types to be applied to object references, primitives, value types, and possibly even void.


SOURCES:


Official doc:

https://openjdk.org/projects/valhalla/

https://en.wikipedia.org/wiki/Project_Valhalla_(Java_language)

https://openjdk.org/jeps/8277163

https://openjdk.org/jeps/401

Παρασκευή 20 Ιανουαρίου 2023

Concurrency with Synchronized keywork and Atomic classes


 
ACHIEVING SYNCHRONIZATION
 FOR A SHARED INSTANCE BETWEEN MULTIPLE THREADS



Lets suppose we have many threads operating simultaneously on an  instance which increments a counter by 1 

But we don't want 2 or more to operate at the same time

Because this will create inconsistencies on our controlled adding - counter may increase faster and lose a value. 

So, only one thread should have access to read and write at each moment.

The next thread should get the last value and increment/write on it.

And so on.



THREADS AND MAIN MEMORY








WITH SYNCHRONIZED KEYWORD



Class/Instance for incrementing counter

public class SynchronizationWithSynchronizedKeyword {
private int counter;

int getValue() {
return counter;
}

synchronized void incrementBy1() {
counter++;
}
}

- Synchronized keyword will:

    - Stop other threads from accessing (locking)
    - Read the last value from the main memory
    - Increment it by 1
    - Write the new value in shared memory




Testing

@Test
public void test1() throws InterruptedException {
ExecutorService service = Executors.newFixedThreadPool(3);
SynchronizationWithSynchronizedKeyword syncWithKeyword = new SynchronizationWithSynchronizedKeyword();

IntStream.range(0, 1000).forEach(count -> service.execute(syncWithKeyword::incrementBy1));
shutdownAndAwaitTermination(service);

assertEquals(1000, syncWithKeyword.getValue());
}
- Shared instance: syncWithKeyword
- We initiate 1000 Runnable tasks via a 3-Thread pool
- These tasks reference the shared instance's increment method
- To pass test, each task should increase the counter variable by 1, adding totally to 1000.



Helper method to gracefully shutdown the executor threads
private void shutdownAndAwaitTermination(ExecutorService pool) {
// Disable new tasks from being submitted
pool.shutdown();
try {
// Wait a while for existing tasks to terminate
if (!pool.awaitTermination(100, TimeUnit.MILLISECONDS)) {
// Cancel currently executing tasks forcefully
pool.shutdownNow();
// Wait a while for tasks to respond to being cancelled
if (!pool.awaitTermination(100, TimeUnit.MILLISECONDS))
System.err.println("Pool did not terminate");
}
} catch (InterruptedException ex) {
// (Re-)Cancel if current thread also interrupted
pool.shutdownNow();
// Preserve interrupt status
Thread.currentThread().interrupt();
}
}
Result: Success





WITH ATOMIC VARIABLE CLASSES



Class/Instance for incrementing counter
public class SynchronizationWithAtomicClasses {
private final AtomicInteger counter = new AtomicInteger(0);

int getValue() {
return counter.get();
}

void incrementBy1() {
counter.incrementAndGet();
}
}
- AtomicInteger's incrementAndGet when called from a thread, will (atomic operation) :

    - Stop other threads from accessing (locking)
    - Read the last value from the main memory
    - Increment it by 1
    - Write the new value in shared memory



Testing

(Same as above)
@Test
public void test2() throws InterruptedException {
ExecutorService service = Executors.newFixedThreadPool(3);
SynchronizationWithAtomicClasses syncWithAtomic = new SynchronizationWithAtomicClasses();

IntStream.range(0, 1000).forEach(count -> service.execute(syncWithAtomic::incrementBy1));
shutdownAndAwaitTermination(service);

assertEquals(1000, syncWithAtomic.getValue());
}
Result: Success



Πέμπτη 27 Ιανουαρίου 2022

Flyweight pattern

  • What problem does Flyweight pattern solve?



Suppose we need to create and log Vehicle objects with random locations, at regular intervals, for an extended period

If we just create "new Vehicle().." every time, we will definitely get and OutOfMemory exception



How are we going to approach this issue?

Consider that we only need new locations. The Vehicle object instantiation is the same every time.



  • How does Flyweight pattern solve this?


We use the Factory pattern to provide the same Vehicle object to the caller, and then we can just set the random locations, and log it

Thus, our memory will now handle only 2 objects (one Truck and one Car)


This VehicleFactory has a vehicles property that holds only one instance of each vehicle type


Finally we use this factory to replace our previous "new Car()..", "new Truck()..", and set location, and log





Τρίτη 16 Μαρτίου 2021

Spring Boot Messaging with JmsTemplate and EmbeddedActiveMQBroker



Spring Boot Messaging with JmsTemplate and EmbeddedActiveMQBroker 







1. Pom.xml


<dependency> <groupId>org.apache.activemq</groupId> <artifactId>activemq-camel</artifactId> </dependency> <dependency> <groupId>org.apache.activemq</groupId> <artifactId>activemq-broker</artifactId> <scope>test</scope> </dependency>



2. Application yml / properties


amq: endpoint: in: some.queue.route.in broker: url: vm://localhost?broker.persistent=false



3. Test Class


@SpringBootTest(classes = {Application.class}, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) @ActiveProfiles({"your-app-yml"}) public class TestClass { @Autowired private JmsTemplate jmsTemplate; @Rule public EmbeddedActiveMQBroker broker = new EmbeddedActiveMQBroker(); @Value("${amq.endpoint.in}") private String amqEndpointIn; /** * Make sure all queues are initialized before starting tests */ @Before public void init() { this.jmsTemplate.browse("some.queue.route2.in", (session, browser) -> 0); this.jmsTemplate.browse("some.queue.route3.in", (session, browser) -> 0); this.jmsTemplate.browse("some.queue.route.in", (session, browser) -> 0); } @Test public void testQueues() throws Exception { // assert again all queues are empty before starting original test assertTrue(broker.getMessageCount("some.queue.route2.in") < 0); assertTrue(broker.getMessageCount("some.queue.route3.in") < 0); assertTrue(broker.getMessageCount("some.queue.route.in") == 0); // trigger jmsTemplate.send(amqEndpointIn, mc -> mc.createTextMessage(message)); jmsTemplate.send("some.queue.route2.in", mc -> mc.createTextMessage(message)); // assert copy-queue not empty, dlq-queue empty assertTrue(broker.getMessageCount("some.queue.route2.in") > 0); assertTrue(broker.getMessageCount("some.queue.route3.in") < 0); } }