`
fengjia10
  • 浏览: 30564 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Immutable Data Structures in Concurrent Java Applications!!!

阅读更多

    Concurrent applications have multiple threads running simultaneously. Access to data shared by multiple threads requires synchronization which is often a source of fragile and hard to maintain code, hard to find bugs, and performance issues. You can minimize synchronization and the headaches that go with it using immutable data structures. In this article I’ll demonstrate how to create and use immutable data structures to reduce and localize the need for synchronization.

    Consider an application that uses a set of contacts. The contacts are stored in a map with the contact name as the key and a Contact object as the value. Various threads in the application access the contacts. Both the Contact class and the map require synchronization. Here is thread safe implementation of the Contact class:

public class Contact { 
    private volatile String name; 
    private volatile String email; 
    private volatile String phone; 

    public String getName() {return name;} 
    public void setName(String name) {this.name = name;} 

    public String getEmail() {return email;} 
    public void setEmail(String email) {this.email = email;} 

    public String getPhone() {return phone;} 
    public void setPhone(String phone) {this.phone = phone;} 
}



    I could have chosen to synchronize all the setters and getters but making the fields volatile is a simpler solution. Using this implementation for the contact objects and ConcurrentHashMap for the contact map provides a thread safe solution. Usually thread safety at the class level alone is not sufficient to support application logic as demonstrated in the following method:

public void handleGmailNotification(Contact contact) { 
    if (contact.getEmail().endsWith("gmail.com")) { 
        sendGmailNotification(contact.getEmail()); 
    } 
} 



    This method is supposed to send a special email to contacts with a GMail address. If another thread changes the contact between the execution of the first two lines of code the GMail specific email may be sent to a non-GMail account. That may only happen once a month and will likely be a difficult bug to find especially if the code that changed the email was added by a developer unaware of the use above. More course grained synchronization can be used to fix the problem but that requires that all code that deals with the Contact’s email address be correctly synchronized. Multiply that by the many different pieces of data being shared by multiple threads in a highly concurrent application and you get fragile, bug ridden, and hard to maintain code. Making Contact immutable alleviates these issues:

public final class Contact { 
    private final String name; 
    private final String email; 
    private final phone; 

    public Contact(String name, String email, String phone) { 
        this.name = name; 
        this.email = email; 
        this.phone = phone; 
    } 

    public String getName() {return name;} 
    public String getEmail() {return email;} 
    public String getPhone() {return phone;} 
} 



    Using the immutable version I can be sure that the Contact object I’m interacting with will not change. If I need to make a change to the email address I create a new Contact object and put it in the contact map in place of the existing one.

    The ConcurrentHashMap, while thread safe, can cause similar issues. This code is supposed to send a text message and an email to every contact:

public void sendMessages(Map contactMap) { 
    sendTextToPhone(contactMap.values(); 
    sendEmail(contactMap.values(); 
} 




    If another thread updates the contact map while this is executing we will have another hard to find bug. You could make the collection unmodifiable using Collections.unmodifiableMap but its not truly immutable. The underlying map can still be modified. Also, you have no way to change the contact list. A map implementation that creates a copy when its modified is a nice alternative. Here’s a simple implementation:

public class ImmutableMap implements Map { 
    private final Map map; 

    public ImmutableMap() { 
        this(Collections.EMPTY_MAP); 
    } 

    public ImmutableMap immutablePut(K key, V value) { 
        Map newMap = new HashMap(map); 
        newMap.put(key, value); 
        return new ImmutableMap(newMap); 
    } 

    public ImmutableMap immutableRemove(K key) { 
        Map newMap = new HashMap(map); 
        newMap.remove(key); 
        return new ImmutableMap(newMap); 
    } 

    private ImmutableMap(Map delegate) { 
        this.map = Collections.unmodifiableMap(delegate); 
    } 

    // All the map methods are simply delegated to the map field. 
    // To conserve space they are not shown here. 
} 



    The immutablePut and immutableRemove methods return a copy of the map with the changes, leaving the original map unchanged. All the methods from the Map interface delegate to the underlying HashMap. Since it is unmodifiable any mutating methods will throw UnsupportedOperationException. Immutable versions of other mutating map methods can be implemented using the same pattern as immutablePut and immutableRemove. You can safely use any instance of this type in any way with no concern about causing issues in other parts of the application or vice-versa.

   Its likely the application we’ve been using as an example will require a central reference to the contact list. Here’s a contact service implementation using the ImmutableMap:

public class ContactService { 
    private final ReentrantLock lock = new ReentrantLock(); 
    private volatile ImmutableMap contacts = new ImmutableMap(); 

    public void addContact(Contact contact) { 
        lock.lock(); 
        try { 
            contacts = contacts.immutablePut(contact.getName(), contact); 
        } finally { 
            lock.unlock(); 
        } 
    } 

    public ImmutableMap getContacts() { 
        return contacts; 
    } 
} 



    There is some synchronization required to ensure that if multiple threads want to add a contact to the central list all additions are maintained correctly. Without the lock, if two threads called addContact at the same time they would each add a different contact to the existing map and the last one assigned would be the only one saved. The other would be lost. The contact must be volatile to ensure all threads calling getContacts will get the updated reference. The synchronization required in this case is very localized and easy to maintain. Any code that gets the contacts from the service can interact with them without synchronization concerns.

    This paradigm works best in cases where updates are infrequent and the data set is relatively small. If updates are frequent or the data set is very large then the copying required can become a performance issue. Don’t let that deter you from adopting this paradigm where you can. Immutable data structures make concurrent programming a much simpler and safer endeavor. It is a proven approach that is fundamental in functional programming languages such as Scala and gaining traction in the object oriented world.

 

1
0
分享到:
评论

相关推荐

    Java 9 Data Structures and Algorithms

    Java 9 Data Structures and Algorithms by Debasish Ray Chawdhuri English | 28 Apr. 2017 | ASIN: B01KM5RLGS | 340 Pages | AZW3 | 4.28 MB Key Features This book provides complete coverage of reactive ...

    immutabilityutil一个开源immutabledata的轮子

    它提供了一种轻量级的解决方案,对于那些不想引入更大库如Immutable.js的项目来说,是一个不错的选择。 在“immutability-util-master”这个压缩包中,可能包含了源代码、示例、测试和文档等资源,供开发者学习和...

    Learning.Scala.Practical.Functional.Programming.for.the.JVM

    You’ll start with Scala's core types and syntax before diving into higher-order functions and immutable data structures. Author Jason Swartz demonstrates why Scala’s concise and expressive syntax ...

    Java - The Well-Grounded Java Developer

    By the end of the book, readers will have gained a solid foundation in Java development and the skills needed to craft robust and maintainable applications in a polyglot environment.

    Big Data Processing Using Spark in Cloud

    The book mainly focuses on the in-depth architecture of Spark and our understanding of Spark RDDs and how RDD complements big data’s immutable nature, and solves it with lazy evaluation, cacheable ...

    Immutable详解及React中实践.pdf

    例如,使用 Immutable.js 库,可以使用 setIn 和 getIn 方法来更新和获取数据,而不是使用原生的赋值和获取方法。这样可以避免共享的可变状态问题,提高应用的性能和可维护性。 Immutable 是一种编程概念,可以解决...

    Functional Programming in C#

    As you explore the many practical examples, you'll learn the power of function composition, data flow programming, immutable data structures, and monadic composition with LINQ. What's Inside Write ...

    Functional Programming in C#(True PDF)

    Functional Programming ... As you explore the many practical examples, you'll learn the power of function composition, data flow programming, immutable data structures, and monadic composition with LINQ.

    java-immutable-collections:Java不可变的基于数组的集合

    ImmutableCollections-基于数组的Java不可变集合 版权所有(c)2017 Nicholas Cull 有关许可信息,请参阅LICENSE.txt。 Java 1.8的基于数组的不可变集合 排序和未排序的变体 风格类似于番石榴收集包装 空友好 Java 8...

    Pragmatic.Clojure.Applied.From.Practice.to.Practitioner.1680

    Discover how to use Clojure in the real world, and unlock the speed and power of this beautiful language on the Java Virtual Machine. Clojure Applied gives you the practical, realistic advice and ...

    Concurrent+Programming+in+Java+-+Design+Principles+and+Patterns,+Second+Edition_

    ### 并发编程在Java中的设计原则与模式(第二版) #### 一、并发对象导向编程 本章节作为本书的开篇,旨在介绍如何在Java编程语言中思考、设计和实现并发程序。大部分内容假设读者已经是一位有经验的对象导向编程...

    Big Data Processing Using Spark in Cloud 2018

    The book mainly focuses on the in-depth architecture of Spark and our understanding of Spark RDDs and how RDD complements big data’s immutable nature, and solves it with lazy evaluation, cacheable ...

    PROFESSIONAL F# 2.0

    This chapter explains why immutability matters and how to work with immutable data structures effectively. - **Data Types (Chapter 15):** Advanced data types, including algebraic data types and type ...

    Clojure High Performance Programming(PACKT,2ed,2015)

    It also highlights the importance of using the right concurrent data structure and Java concurrency abstractions. This book also sheds light on performance metrics for measuring, how to measure, and...

    immutable在redux中的使用

    什么是immutable Data? Immutable Data 就是一旦创建,就不能再被更改的数据。对 Immutable 对象的任何修改或添加删除操作都会返回一个新的 Immutable 对象。Immutable 实现的原理是 Persistent Data Structure...

    Java Concurrency in Practice

    《Java Concurrency in Practice》是Java并发编程领域的一本经典著作,由Brian Goetz、Tim Peierls、Joshua Bloch、David Holmes和Doug Lea等多位Java并发领域的专家共同编写。这本书深入浅出地讲解了Java编程中的多...

    java英文笔试

    These questions cover a range of fundamental concepts in Java, including database technology, object-oriented programming, data structures, and concurrency. Understanding these topics is crucial for ...

    ImmutableObjects

    ### Immutable Objects in Java 在Java编程语言中,不可变对象(Immutable Objects)是一个重要的概念,尤其是在构建健壮、易于维护的应用程序时。本篇将基于提供的文件内容来深入探讨不可变对象的概念及其在Java中...

    Java 9 with JShell

    The release of Java 9 has brought many subtle and not-so-subtle changes to the way in which Java programmers approach their code. The most important ones are definitely the availability of a REPL, ...

Global site tag (gtag.js) - Google Analytics