Site Search:

UnsafeVectorHelpers.java and SafeVectorHelpers.java

<Back


The following example shows, although vector is thread safe, getLast and deleteLast didn't use client-side locking to guard compound actions. As a result, getLast sometimes can through ArrayIndexOutOfBoundsException.

import java.util.Vector;

public class UnsafeVectorHelpersTest{
    public static void main(String...args) {
        Vector<String> list = new Vector<String>(10);
        for(int i = 0; i < 10; i++) {
            list.addElement("a");
        }
        System.out.println(list.size());
        new Thread(new Runnable(){

            @Override
            public void run() {
                UnsafeVectorHelpers.deleteLast(list);
                
            }}).start();
        UnsafeVectorHelpers.getLast(list);
    }
}

class UnsafeVectorHelpers {
    public static Object getLast(Vector list) {
        int lastIndex = list.size() - 1;
        return list.get(lastIndex);
    }

    public static void deleteLast(Vector list) {
        int lastIndex = list.size() - 1;
        list.remove(lastIndex);
    }

}


The synchronized collection classes guard each method with the lock on the synchronized collection object itself, synchronized collections also supports client-side locking. By holding the vector as the
client-side lock, we can make the getLast and deleteLast atomic, thus fixed the check-then-act race condition we observed in UnsafeVectorHelper. We should not use this as the client-side lock, because this lock refers to the intrinsic lock of SafeVectorHelper, which is the wrong lock -- the vector guard each method with vector's intrinsic lock instead of the the caller's intrinsic lock (SafeVectorHelper)


import java.util.Vector;

public class SafeVectorHelpersTest{
    public static void main(String...args) {
        Vector<String> list = new Vector<String>(10);
        for(int i = 0; i < 10; i++) {
            list.addElement("a");
        }
        System.out.println(list.size());
        new Thread(new Runnable(){

            @Override
            public void run() {
                SafeVectorHelpers.deleteLast(list);
                
            }}).start();
        SafeVectorHelpers.getLast(list);
    }
}

class SafeVectorHelpers {
    public static Object getLast(Vector list) {
        synchronized (list) {
            int lastIndex = list.size() - 1;
            return list.get(lastIndex);
        }
    }

    public static void deleteLast(Vector list) {
        synchronized (list) {
            int lastIndex = list.size() - 1;
            list.remove(lastIndex);
        }
    }

}