What is feels like to have poor communication skills in a meeting

Today a satirical video about what it feels like to be the only engineer in a meeting has been making the rounds. I’m not going to link to it, but I’m sure you can find it. While the video has some funny moments, it is sad to see the way this has been spreading like wild fire in the software community.

I feel like this is exactly the kind of video that alienates outsiders from the community and feeds the stereotype of engineers as pretentious, noncooperative and uncommunicative people. While the video itself isn’t really even about engineers specifically, the community fervor and treatment of it as if it is some kind of brilliant satire on the struggle we are forced to live through every day is absurd.

In software engineering, your ability to communicate effectively (with other engineers and non-engineers alike) is arguably the most important skill. It is sad to see so many people feel that they can identify strongly with this video. If you consistently feel exasperated by your colleagues inability to comprehend your simple, elegant explanations, then it is likely those explanations aren’t as simple or elegant as you think.

I know this is just a silly video, but it struck a nerve. Communication is a two way exchange and more often than not, failure lies with the delivery not the reception. Being an engineer doesn’t automatically make you the smartest person in the room and relishing in having squirreled away knowledge from your coworkers isn’t productive or healthy.

  • Twitter
  • Facebook
  • RSS
  • HackerNews
  • Reddit

remove_const

In testing, it is often nice to override a constant to test configuration dependent behavior. Ruby will scream at you when you do, creating unnecessary and annoying logging artifacts in your test suite.

it "should have monkeys" do
 MonkeyModule::HAS_MONKEYS = true
 MonkeyModule::HAS_MONKEYS.should == true
end

This code would work but it spits out these nasty warnings.

./monkey_spec.rb:62: warning: already initialized constant MonkeyModule::HAS_MONKEYS
./monkey_config.rb:2: warning: previous definition of HAS_MONKEYS was here

Today I found the helpful Module function remove_const. Call it before reassigning and the warnings are gone.

it "should have monkeys" do
 MonkeyModule.send(:remove_const, "HAS_MONKEYS")
 MonkeyModule::HAS_MONKEYS = true
 MonkeyModule::HAS_MONKEYS.should == true
end
  • Twitter
  • Facebook
  • RSS
  • HackerNews
  • Reddit

3 Ways Employers Can Communicate Their Culture

This post originally appeared on The Parklet Blog

This tweet by @nancyrubin got me thinking about what employers can be doing to communicate their culture both to current employees and potential hires. Before diving into some practical advise, I want to quickly address why consistently communicating your culture is important.

When dealing with potential hires, accurately conveying company culture is vitally important because it can save you many thousands of dollars from failed new hires. Screening for a strong culture fit has to be a top priority because, regardless of other factors, culture fit will make or break a successful onboarding and assimilation for a new employee.

In addition to preventing failed hires, demonstrating a strong company culture during the interview process can be the deciding factor that sets your company apart. The talent market can be fierce and anything that can give you that extra edge over your competition is going to be worth it.

Consistently reinforcing company culture with existing employees is important too. It helps employees maintain excitement for their work and makes unifying the organization easier. When employees can readily see how the company’s culture and vision links to their day to day work, they will be more satisfied, creative and productive.

That’s all well and good, but how do you do it? Below are 3 great tips for communicating your company’s culture.

Be Explicit

Company culture is much more than the ping pong table in the office. You need to identify the core tenants that make your company unique. They can be just about anything so long as they are well defined and important to your organization. Once you’ve identified what those are, you should be very explicit about demonstrating how they impact decision making.

For example, if your company values transparency then you should explicitly call this out in the interview process. Proactively engage your candidates about what the hiring process is, where they stand in it, and explain that they can expect a high degree of openness because that is part of your culture.

Another example would be that if your company loves remote working, have a policy that forces new hires to spend a day in their first week working from home. Let them know this policy is to help them get used to your distributed environment and to demonstrate that remote working is a core tenant of your organization.

Identifying your core cultural values and explicitly calling them out helps employees truly understand the work place. They will feel more confident about making decisions that align with the company, and you will have a happier, more productive work force.

Be Consistent

Company culture can often get lost in translation because it is not consistently applied. Everyone from the CEO to the line manager to the HR director needs to demonstrate that they value and respect the company’s culture.

For example, if your company values work/life balance then you need to be sure it is consistently applied. If line managers are encouraging employees to work long hours in order to meet a deadline or the CEO is consistently pulling all nighters then it doesn’t matter how many times you say to your employees that balance is important. They will hear the real message, which is that the company expects long hours and doesn’t care about balance.

When leadership ignores cultural tenants or just gives them lip service, employees are not going to be bought in. You can’t fake it.

Be Honest

Your company culture is what makes your organization unique. Don’t try to force whatever the latest trends are onto your team. Be honest with yourself as a company and your team. If you are a work hard/play hard team that celebrates the 100 hour work week, then don’t try to sugar coat it for candidates. It won’t work in the long run, and it may even cost you some great hires that actually love that kind of environment.

Furthermore, when defining your culture, be sure your definition reflects reality rather than wishful thinking. Mislabeling yourself will do more harm than good. It will make identifying issues more difficult and leave you with confused employees.

Company culture is a big topic, and there is no one size fits all recipe for implementing it. But, if you are honest, consistent and explicit when communicating it to your employees and potential hires, then you will be surprised by how effective your team can be.

What other tips do you have for effectively communicating company culture?

  • Twitter
  • Facebook
  • RSS
  • HackerNews
  • Reddit

Optimizing Employee Offboarding

This post originally appeared on The Parklet Blog

Whether an employee is moving on for new opportunities or you’ve been forced to let someone go, employee offboarding is an important process you should work to optimize. If done properly, you can part ways amicably and gain a company advocate where you lost an employee. Especially in the case of an employee voluntarily leaving, it is also an important data gathering opportunity.

Creating a Company Advocate

Creating a company advocate out of an exiting employee is all about managing a considerate and organized offboarding experience. Be prepared and professional. Your goal is to alleviate unnecessary stress and free up the employee to wrap up unfinished work and have final meetings with coworkers.

The first thing you should do upon starting the process is give the employee a schedule based on their final day. This makes it clear you are on top of the situation, and it will immediately answer most questions about the process. With that schedule, you should be sure to address all of the bureaucratic issues. Simply being forthcoming about issuing final paychecks, collecting company equipment and signing paperwork goes a long way toward leaving the employee with a positive final impression.

Just laying out the process isn’t enough though. You need to make sure everyone involved is on the same page. Be sure that HR has the paperwork ready, IT knows when to collect equipment and disable accounts, accounting issues a final check, and managers schedule exit interviews. The last thing you want is to find out something fell through the cracks after the employee is already out the door.

After crossing all of the t’s and dotting all of the i’s, it is important to have a candid, respectful one-on-one with the employee. Your goal, in addition to gathering valuable feedback (which I will address below), should be to establish a mutual respect and bring a healthy, happy close to the company-employee relationship. Allow the employee to candidly discuss the company. Let them do most of the talking and never have an argument. Ensure the employee that there are no hard feelings and that the company wants nothing but the best for them. This is vitally important because many employees will be scared of retaliatory behavior, like a negative reference.

By being prepared, professional and respectful during the offboarding process, you can often turn even a highly negative departure into a company win.

Collecting Valuable Feedback

In addition to bringing a healthy close to the relationship, it is important to gather feedback from the employee. Offboarding is one of the most valuable opportunities to collect data that will uncover insights about employee satisfaction, organization structure and management practices. Your goal should be to discover anything that can help you prevent future departures, voluntary or otherwise.

Exit Interview

The obvious opportunity to collect this feedback is the exit interview. There are some simple formatting guidelines you can follow to help improve the process.

First, keep it short. Don’t have a 3 hour gantlet of a meeting that you both dread all week. Set aside enough time for a full conversation but don’t draw things out and don’t run long.

Conduct the interview in a one-on-one fashion. Avoid ganging up on the employee and always perform the interview with someone other than the employee’s direct manager. This is very important because you want the employee to speak freely, and there is often valuable information to gather on management styles and personalities.

Keep it consistent. Always ask the same basic set of questions and take written notes. This is important because you want to be able to compare data across exit interviews conducted by disparate interviewers. A great way to still have an opportunity to collect additional, unformatted feedback is to begin the interview by letting the employee describe their time at the company.

And finally, just to re-iterate because it is so important, never argue with the employee during the exit interview. It can be very common for the employee to get angry. That is fine, but you should never reciprocate. Just let them speak their mind.

Written Survey

In addition to conducting a well structured exit interview, you should have a written exit survey. The questions should be very similar to the regular employee surveys you do. Ensure the employee the data will only be used in an anonymized fashion.

Focus on measuring employee satisfaction with respect to important aspects of the company like management style, team size, career growth opportunities and quality of work. Use the data to inform decisions designed to prevent future churn and recognize disgruntled or under performing employees before they become issues.

Churn is never a good thing, but by providing a consistent, high quality offboarding experience, focused on creating company advocates and collecting data, you can set yourself apart as a company.

What are the best and worst experiences you’ve had with the offboarding process? How could they have been better?

  • Twitter
  • Facebook
  • RSS
  • HackerNews
  • Reddit

3 Must Haves for a Great Company Culture Document

This post originally appeared on The Parklet Blog.

One of the often overlooked, but extremely important, company artifacts is the culture document. It could be a slide deck, a internal website or part of the employee handbook. The format isn’t important, but it must be accessible and it needs to have the right content.

Your culture document should tell the story of your company. After reading it, I should know how you got to where you are, what things are important to you as an organization and where you are going. You can answer those questions in a lot of different ways, but there are some common elements you can almost always find.

Mission Statement

The idea or purpose that drives your organization is central to a strong culture. It should be clear, concise and unique. It should serve as a guide for defining your values and as the legend to your journey’s map. All of the people you work with should be united around it. Include it early and prominently in your culture document.

Company History

Every company has a storied history, full of moments that make it unique and that come together to make the company what it is today. Taking the time to capture that history is well worth it. It gives new employees a great starting point for understanding the organization and an immediate sense of belonging. It is also a great tool you can continuously use to keep things in perspective.

Company Values

All great companies have guiding principles they can turn to when making tough decisions. They are usually honest, specific and opinionated. They need to be explained thoroughly and shared readily. It is important that every employee knows and believes in them. One of the easiest ways to do this is by making your culture document accessible and emphasizing its importance to new hires.

Final Thoughts

These elements will serve as a strong foundation for building a great company culture, not just a document. Keep in mind that as your company grows, so will the challenges of maintaining a strong cohesive culture. Having a well defined and oft referenced document will be a great tool to help.

I hope this gives you a basic idea of how to build up a great culture document. What other elements have you found most useful when defining your company’s culture?

  • Twitter
  • Facebook
  • RSS
  • HackerNews
  • Reddit

Playing with Prolog

I’ve been thinking a lot about logic programming lately. So today when a buddy of mine sent out a fun little puzzle, I decided it would be a nice excuse to bust out some Prolog. Of course that comes with the obligatory install, setup and orient steps. It is pretty painless though. Here’s the run down.

Install and run interpreter:

brew install swi-prolog
swipl

Some basic I found helpful:

['src.pl']. /* Load a file from source */
halt. /* Exit interpreter */
; /* View next result */

Anyways, the puzzle I wanted to solve was this:

The Absent-Minded Teller
An absent-minded bank teller switched the dollars and cents when he cashed a check for Mr. Brown, giving him dollars instead of cents, and cents instead of dollars. After buying a five-cent newspaper, Mr. Brown discovered that he had left exactly twice as much as his original check. What was the amount of the check?

My solution:

check([ORIGINAL]) :-
	between(101,10005,ORIGINAL),
	between(1,99,DOLLARS),
	between(1,99,CENTS),
	X is (DOLLARS * 100) + CENTS,
	ORIGINAL is (X - 5) / 2,
	ORIGINAL is (CENTS * 100) + DOLLARS.

I won’t spoil it for you, but if you call the function above you’ll get the answer.

It is always fun to dust off a programming language I haven’t touched since University, even if just to solve a simple puzzle.

  • Twitter
  • Facebook
  • RSS
  • HackerNews
  • Reddit

for…in

Cruising MDN today looking for trouble and came across this little tidbit.

for..in should not be used to iterate over an Array where index order is important. Array indexes are just enumerable properties with integer names and are otherwise identical to general Object properties. There is no guarantee that for...in will return the indexes in any particular order and it will return all enumerable properties, including those with non–integer names and those that are inherited.

That means you can do the following:

var ary = ["foo", "bar", "baz"];
ary.bing = "boom";
Object.prototype.blamo = "bingo";

for (var x in ary) {
  console.log(x);
}

And conceivably get output like this:

0
2
"bing"
1
"blamo"

Fun stuff.

  • Twitter
  • Facebook
  • RSS
  • HackerNews
  • Reddit

Graph Search First Thoughts

When I saw the press announcements about Facebook’s new Graph Search, nothing clicked that made me want to use it. That changed last night.

At dinner a friend told me about a new app that let you rent scooters on the fly. I wanted to try it out. I knew it was called Scoot but I didn’t know their website. So naturally I Googled it. What’s wrong with this picture?

Screen Shot 2013-01-16 at 8.42.27 AM

Every search result is an article talking about the service, not a single link to the actual service. You won’t find the real link until the very last result. Clearly something is seriously wrong when Google returns 9 results talking about something before the thing being talked about. This got me thinking about how I really relate to the things I’m looking for. I sat down and thought “Hey, I want to look up that scooter thing in the city that my friend Matt told me about tonight”. Shouldn’t I be able to search “Scooter service that Matt likes”? Well that is exactly what Graph Search is for.

I’m not yet in the beta so I can’t say whether or not it would have worked, but I am excited to find out.

Also, Scoot is awesome. Check it out.

  • Twitter
  • Facebook
  • RSS
  • HackerNews
  • Reddit

New Year’s Resolutions: Is there a better option?

Yikes! Already 3 days behind...

It’s that time of year again where the question of New Year’s Resolutions comes up in just about every conversation. The answer I am hearing most often this year seems to be something to do with reading more. This is interesting because the answer I gave last year was “I will read 25 books this year”. Each time I hear this answer, I ask myself “How well did I do on this resolution last year?”.

It turns out that this is a harder question to answer than it seems. I have a distinct feeling that I read more than in recent years but I’m also pretty sure I missed the 25 books mark by a decent bit. Or in other words, I’ve got no idea. Of course I could try to think back and count the books, but memory is tricky and I certainly don’t trust mine. Besides, it wouldn’t really help solidify the feeling that I read more this year generally (which is what I really care about). I don’t know how I would count the short stories or academic papers much less the hundreds of blog posts either. Essentially, from day one I was hopelessly ill-equipped to fulfill my resolution last year.

This always leads me to thinking about just how incredibly high the failure rates are (article about why). In fact, many of the resolution conversations I have with people are essentially tongue-and-cheek in nature because people are already resolved to fail before they even start. This is scary to think about because the resolutions people mention usually map to real, strong, personal desires. Large portions of people have started their year by sarcastically writing off their ability to succeed at bettering themselves in at least one important way. Yikes, if that’s true, you could argue that New Year’s Resolutions have the opposite impact on society as intended.

If New Year’s Resolutions don’t work, then what does? Dr. BJ Fogg, of Stanford Persuasive Tech Lab, makes a strong argument for looking at habit forming like any other skill in that it takes practice to acquire and you need to start small. Dr. Fogg runs a program called Tiny Habits that focuses on how to build the skill of forming habits. In that program, he focuses on simplicity, positive feedback, and “anchoring” new habits to existing ones. I encourage you to join me next week in participating in one of the Tiny Habits sessions.

In addition to simply building raw habit forming skill, it is interesting to be able to bring a ruler to the table when measuring that skill. I strongly believe the old credo “Knowledge is Power” and I think that having the data to calculate progress and understand your state is a powerful tool. At the gym, you can measure exactly how strong you are because you can count the weights you lift. To make a simliar measurement of habit forming skill, you need a similarly easy thing to count. That means data. Luckily, technology has reached the point that simple Quantified Self style measurements take only a few seconds a day using apps like Lift or a simple repeat GMail task list (There are tons of these apps, some crazy ones too).

I plan on starting to build some of this data around some larger habits I have already formed. In the style of Dr. Fogg’s Tiny Habits program, one of my three habits will be: “After my morning shower, I will record the last day’s progress in Lift”. Note that the habits I am recording in Lift are things that I have already established strongly, not habits I am trying to form. The hope being that I can at a future date use the combination of an improved habit forming skill and a data driven base line to start with a leg up on altering those existing larger habits.

So, I guess you could say, my New Year’s Resolution for 2013 is to improve and quantify my habit forming skill…

  • Twitter
  • Facebook
  • RSS
  • HackerNews
  • Reddit

Concurrency and Multi-Threaded Programming in Java – Part 2

This is the second part in a three part discussion about concurrency in Java. The first article introduces the common terminology used and how many of the basic locking mechanism work. This post will focus on the java.util.concurrent package. The final post will discuss some of the more complicated issue that arise in Java when using concurrency and synchronization.


Before talking about the java.util.concurrent package I want to go over how a couple of the Java keywords effect concurrency in Java 1.5+. In an effort to maintain good performance, when synchronization is not explicitly dictated, the compiler, JVM and cache take serious liberties with reordering memory operations. This can provide significant performance gains but also can cause your programs to function in unexpected ways. The only rule on reordering is that the thread that is currently executing can’t tell the difference. This is called within-thread as-if-serial semantics. Luckily, rules are added with the use of the keywords volatile and final.

The volatile keyword guarantees that reads and writes to those variables are ordered totally across all threads; meaning that neither the compiler or cache can reorder these calls with each other. Furthermore, volatile reads and writes will not be reordered with any other memory operations. So this means that when thread A writes to a volatile variable X, and thread B reads from X, any variables that were visible to thread A at the time X was written will also be visible to B. This means that X can be used to indicate state to other threads. There are also similar guarantees when a thread is started, a thread is joined with another thread and when a thread enters and exits a synchronized block.

The final keyword means just that final, except when it doesn’t… Before Java 1.5, without synchronization another thread could potentially see the default value (null or 0) for a final field and then later see the correct value. Java 1.5+ now guarantees that when a final object’s constructor completes that all final fields are frozen and that any other threads that reference the object will see the correct values from those fields. Like volatile, operations that initialize final fields also will not be reordered with operations that follow the freeze. Beyond this, any variable that can be reached through a final field are also guaranteed to be visible to other threads. The impact of this is that immutable objects are inherently thread-safe.

java.util.concurrent

The concurrency library was added in Java 1.5. The library uses hardware level constructs such as compare and swap (CAS) to create thread safety mechanisms largely without the need for locking at the object level. This generally provides a significant performance increase over using the synchronized keyword to lock critical paths (the performance improvement can become a performance hit in extremely heavy traffic situations where extended periods of waiting are necessary because many of these algorithms poll rather than sleep and therefore waste CPU cycles). It is usually advisable to use the canned implementations from this package rather than implementing your own class. The concurrent package introduces the first truly thread safe data structures to the standard library. You can see the full documentation here. I am going to go over a couple of the most useful and a few of the interesting classes in the package and give some usage examples.

Semaphore

This class is very straight forward. It works primarily through the acquire() and release() methods. This implementation simply keeps an internal count variable that controls access. The primary use case is for restricting access to a limited resource. In the example below we use a semaphore to control a finite number of available db connections.


public static class DbConnectionFactorExample{

    public static final int NUM_CONNECTIONS = 10;
    private static final String DB_URL = "jdbc:mysql://localhost/exampledb";

    public static Connection getConnection(){
        try{
            return LimitedConnectionDecorator.getConnection();
        }catch(InterruptedException e){
            return null;
        }
    }
}

class LimitedConnectionDecorator implements Connection{

    private static final Semaphore connectionAccess = new Semaphore(NUM_CONNECTIONS);
    private Connection dbConnection;

    public LimitedDBConnection(Connection dbConnection){
        this.dbConnection = dbConnection;
    }

    public static Connection getConnection() throws InterruptedException{
        connectionAccess.acquire();
		try{
        	return new LimitedDBConnection(DriverManager.getConnection(DB_URL));
		}catch(SQLException e){
			connectionAccess.release();
			return null;
		}
    }

    @Override
	public void close() throws SQLException{
	    if(!dbConnection.isClosed()){
	        try{
	            dbConnection.close()
	            connectionAccess.release();
	        }catch (SQLException e){
	            //Roll back logic
	            //May release lock anyways depending on db
            }
        }
    }
    //... rest of implementation omitted
}

Exchanger

The exchanger is an interesting convenience class that facilitates the coordinated exchange of a data structure between two threads. Once the first thread finishes processing the object it calls exchange(object) and waits for the other thread to be done as well. Then they swap. The obvious use case here is for having one thread fill and one thread empty that structure. In the example below, I do just that.


public class ExchangerExampler{

    public Exchanger<MagicDataStructure> exchanger = new Exchanger<MagicDataStructure>();

    public MagicDataStructure mds1 = new MagicDataStructure();
    public MagicDataStructure mds2 = new MagicDataStructure();

    public static void main(Strings args[]){
        new Thread(new Filler()).start();
        new Thread(new Emptier()).start();
    }

    class Filler implements Runnable {
        public void run(){
            MagicDataStructure myMds = mds1;
            try{
                while(true){
                    if(myMds.isFull()){
                        myMds = exchanger.exchange(myMds);
                    }
                    myMds.fill(new MagicStuff());
                }
            }catch(InterruptedException e){e.printStackTrace();}
        }
    }

    class Emptier implements Runnable {
        public void run(){
            MagicDataStructure myMds = mds1;
            try{
                while(true){
                    if(myMds.isEmpty()){
                        myMds = exchanger.exchange(myMds);
                    }
                    myMds.empty();
                }
            }catch(InterruptedException e){e.printStackTrace();}
        }
    }

}

FutureTask

The FutureTask class is interesting because it basically combines a Thread with a method. When you spawn a thread you are basically just creating an asynchronous computation. The FutureTask wraps this up and allows that computation to return a result. You create a FutureTask by passing in a Runnable and, optionally, the result to be returned. You now start the FutureTask and then get() can be called some time later in the future. If the task has completed then get() will return the result, otherwise it will block until the result is finished being computed. Below is a simple example implementation.


public class FutureTaskExample{

    public static void main(String args[]){
        //Do you get it? It's a computater...
        FutureTask computater = new FutureTask(new OverclockedPotato());
        computater.run();
        //Do other awesome computing
        //....
        Object frenchFries = computater.get();
    }

}

class OverclockedPotato implements Callable{

    public Object call(){
        potato = new Object();
        //Do stuff to it
        return potato;
    }
}

CopyOnWriteArrayList

The previous examples were all nice concurrency constructs but now let’s talk about some of the interesting data structures provided by the concurrent package. The CopyOnWriteArrayList is a completely thread safe List designed to be used in situations where traversals occur significantly more often than mutation. In this case it is beneficial to be able to iterate over the List without locking. This is a common need when a List is used to hold Listeners such as in AWT or Swing applications. CopyOnWriteArrayList accomplishes lock-less iteration by creating a copy of the List when a mutation occurs. This allows iteration to guarantee that it will return the list in the same state as at the time it was constructed. What this means is that the CopyOnWriteArrayList holds a mutable reference to an immutable array, rather than the other way around. I’m not going to include a code sample here because the use is identical to that of a normal list and it is the use case and data structure implementation that is interesting.

ConcurrentHashMap

The ConcurrentHashMap is an extremely interesting class that provides complete thread safety with minimal locking. It is optimized for the most common operation, retrieving an element that already exists in the map, and can succeed without locking the majority of the time. In a highly parallel system with many threads interacting with the map the performance excels far beyond that of a synchronizedMap or a HashTable. Several neat tricks are used to accomplish this.

First, rather than having a single object wide lock, the ConcurrentHashMap has a lock for each bucket (or however many you want as this value can be set in the constructor). This means that theoretically that many threads can be writing to the Map all at once. While in practice it will be lower, it is still significantly higher than only one.

The second trick takes advantage of the JMM rules on immutability. All of the fields that make up the Map are final except for the entry value fields, which are volatile. What this means is that elements cannot be added or removed from anywhere but the front of the hash chain. Although you can’t know if you are at the head or not, this does guarantee that if you have a reference into the hash chain that the rest of the list won’t change its structure. Since the entry value is volatile, you are also guaranteed to see any updates to the field immediately, thus avoiding the potential for a stale view of memory.

The get() operation begins by getting the head reference in the desired bucket, without locking. It then traverses the chain looking for the value. If it is not found then a bucket lock is acquired, the head pointer is found again and it traverses again. Below is a simplified partial implementation.

public Object get(Object key){
    int hash = hash(key);
    //First pass without locking.
    HashEntry[] tab = table;
    int i = hash & (tab.length-1);
    HashEntry head = tab[i];
    HashEntry e;
    for(e=head; e!=null; e = e.next){
        if(e.hash == hash && equal(key, e.key)){
            Object value = e.value;
            if(value != null){//null value indicates the element has been removed
                return value;
            }else{
                break;
            }
        }
    }
    //Second pass with a lock
    Segment seg = segments[hash & SEGMENT_MASK];
    synchronized(seg){
        tab = table;
        i = hash & (tab.length-1);
        HashEntry newHead = tab[i];
        if(e != null || head != newHead){
            for(e=newHead; e!=null; e=e.next){
                if(e.hash == hash && equal(key, e.key)){
                    return e.value;
                }
            }
        }
        return null;
    }
}

The remove() operation can’t simply remove the element from the chain because it is possible that other threads traversing that chain would see the stale value. Instead removal begins by finding the correct element and sets the value to null. Since the field is volatile, any threads that check this value will immediately see the null value and know that they need to re-traverse the chain with a lock. Then the elements from the head of the chain to the removed element is cloned and joined to the remainder of the chain.

I highly recommend you read through the complete class implementation. It is a really well thought out piece of code that minimized the impact of locks and is cognizant of how the JMM rules works.

I hope this article built on the basic knowledge introduced in Part 1. You should now be familiar with the kind of tools provided by the java.util.concurrent package. It contains a variety of helper class both for building data structures that are thread-safe and for controlling synchronization. When doing multi-threaded programming this should be one of the first places you look for tools to facilitate your needs. You are hopefully also now more confident in your understanding of the effects that using final and volatile keywords has on program execution. In Part 3 of this series I am going to go into some examples of problems that can arise from seemingly harmless code, including incorrect use of the volatile keyword, this references that escape during construction, how to use ThreadLocal to render a stateful class thread-safe and using fork-join to split a workload into multiple tasks.

I am by no means an expert so I welcome any comments, corrections or requests for additional information in this series. I think this is an important and poorly understood topic and I would like to provide a strong introduction here.

  • Twitter
  • Facebook
  • RSS
  • HackerNews
  • Reddit