简体   繁体   中英

how to improve the performance of the following java method to delete elements from a Linkedlist

A thread safe method to delete nodes from a Linkedlist.

 public void delete(String x, LinkedList<String> list)
   {
      String lock = "false";
        for (int i = 0; i < list.size(); i++) {
            synchronized (lock) {
                if (list.get(i).equals(x)) {
                    lock = "true";
                    list.remove(i);
                }
                lock = "false";
            }
        }
   }

Many thanks!

Edit: the above method is thread safe but its performance needs to improve. It is an interview question.

  1. synchronizing on an object that is local to the method isn't really doing anything useful. Also, overwriting the reference to the object you're locking on inside the synchronized block is confusing in purpose. Some explanation on the purpose of that code might help us help you improve it :)

  2. The actual question. get(i) and remove(i) both require you to iterate the list out to position i. If you use the list's actual iterator and the iterator's remove method, you will only have to iterate the entire list once.

Thread-safe:

public void delete(String x, LinkedList<String> list) {
    synchronized (list) {
       for (Iterator<String> it = list.iterator(); it.hasNext();)
            if (it.next().equals(x)) it.remove();
    }
}

But, in all probability, your problem wasn't thread safety. You used list.delete() while iterating through the list and got ConcurrentModificationException . If that is the case, feel free to remove synchronized block.

I would use List.removeAll

List<String> list = new LinkedList<>();
list.addAll(Arrays.asList("a,b,c,d,a,b,c,d,e,a,b,a,b".split(",")));
System.out.println("Before removeAll(a) " + list);

list.removeAll(Collections.singleton("a"));

System.out.println("After removeAll " +list);

prints

Before removeAll(a) [a, b, c, d, a, b, c, d, e, a, b, a, b]
After removeAll [b, c, d, b, c, d, e, b, b]

Try using out-of-box Java Collections API functionality for synchronized collections. Official documentation.

And also you could use an iterator to remove items. As documentation states:

If an explicit iterator is used, the iterator method must be called from within the synchronized block. Failure to follow this advice may result in nondeterministic behavior.

public void delete (String x, LinkedList<String> list) {

            synchronized (list) {
                Iterator<String> it = list.iterator();
                while (it.hasNext()) {
                    String y = it.next();
                    if (x.equals(y)) {
                        it.remove();
                    }
                }
            }
        }
public void delete(String x, LinkedList<String> list){
    Set<String> target = Collections.singleton(x);
    synchronized (list) {
        list.removeAll( target );
    }
}

Two things:

  1. Synchronizing on a string you just created does nothing (well, not exactly, since "false" is an interned string, all pieces of code that synchronize on "false" will be synchronized, but that's a hackish way to get application-wide synchronization, and probably not at all what you intended). You should be synchronizing on the list. Everyone using the list should be synchronizing on the list. Although better practice would be to use a synchronized collection in the first place, eliminating the need for an explicit synchronized block in the using code.
  2. removeAll is usually the most efficient method to remove all occurrences of one or more objects from a collection. In the worst case it is equivalent to iterating over the collection and using the iterator to remove the items (which is the case of LinkedList ), but for some implementations (like ArrayList ) it is made to be more efficient.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM