简体   繁体   English

当没有线程保存某些对象时,如何从ConcurrentHashMap中删除项目?

[英]How Can I remove an item from ConcurrentHashMap when no have a thread holding certain object anymore?

Supposing I have a temporary collection (ConcurrentHashMap) to hold a reference for a certain object, eg, a HttpSession. 假设我有一个临时集合(ConcurrentHashMap)来保存某个对象(例如HttpSession)的引用。 While at least one thread is using a session (in the moment of a request), it can't be removed. 当至少一个线程正在使用会话时(在请求时),无法将其删除。 But, when no more threads are using a session concurrently, it should be removed to release memory. 但是,当没有更多线程同时使用会话时,应将其删除以释放内存。 I tried implement a example similar to that, but I got a NullPointerException. 我尝试实现类似于该示例的示例,但出现了NullPointerException。 What I'm doing wrong? 我做错了什么? :( :(

    class Elem {
      // AtomicInteger saldo = new AtomicInteger(1000);
      Integer saldo = 1000;
    }

    class Sum implements Runnable {

    Map<String, Elem> saldos;
    AtomicInteger n;

    public Sum(Map<String, Elem> saldos, AtomicInteger n) {
        this.saldos = saldos;
        this.n = n;
    }

    @Override
    public void run() {

        Random rand = new Random();

        int r = rand.nextInt(1000);

        Elem e = this.saldos.get("saldo");

        //Null Pointer Exception occurs here!
        synchronized (e) {

            this.n.incrementAndGet();

            if (r % 2 == 0) {

                Integer saldoLido = e.saldo;

                e.saldo += r;

                Integer saldoAtual = e.saldo;

                System.out.println("saldo lido: " + saldoLido + " somado: " + r
                                   + " saldo atual: " + (saldoAtual) + " "
                                   + System.currentTimeMillis());

            } else {

                Integer saldoLido = e.saldo;

                e.saldo -= r;

                Integer saldoAtual = e.saldo;

                System.out.println("saldo lido: " + saldoLido + " subtraído: "
                                   + r + " saldo atual: " + (saldoAtual) + " "
                                   + System.currentTimeMillis());
            }


             if(this.n.decrementAndGet() == 0)
                 this.saldos.remove("saldo");

        }

    }

    }

    public class Main {

    public static void main(String[] args) throws Exception {

        Map<String, Elem> saldos = new ConcurrentHashMap<>(20, 0.9f, 1);

        AtomicInteger n = new AtomicInteger(0);

        saldos.put("saldo", new Elem());

        ExecutorService exec = Executors.newFixedThreadPool(20);

        try {

            for (int i = 0; i < 20; ++i)
                exec.execute(new Sum(saldos, n));

            exec.shutdown();

            while (!exec.isTerminated()) {}

            System.out.println("got elem: " + saldos.get("saldo") + " " + n);

        } catch (Exception ex) {

            exec.shutdownNow();
            ex.printStackTrace();
        }

    }

    }

I put together a working example for you that may help you with your issue. 我为您整理了一个可行的示例,可以帮助您解决问题。 I made Main a junit test to make it easy to run in your favorite IDE or elsewhere. 我对Main进行了junit测试,以使其易于在您喜欢的IDE或其他地方运行。

A couple of points to note. 需要注意的几点。

A CountDownLatch was added so that all threads would complete before the executor service was shutdown and the result printed out. 添加了CountDownLatch,以便在关闭执行程序服务并打印出结果之前,所有线程都将完成。

Elem uses an AtomicInteger so the synchronized block is no longer necessary. Elem使用AtomicInteger,因此不再需要同步块。

The most important fix to the code was to increment the counter in the constructor of the Sum class so that the Elem wasn't removed from the map until each thread had a chance to process. 该代码最重要的修复方法是在Sum类的构造函数中增加计数器,以便在每个线程都有机会处理之前,不会从映射中删除Elem。 Otherwise, it was possible for a thread to run all the way through and remove the Elem before other threads got a chance to execute. 否则,一个线程可能会一直运行并删除Elem,然后其他线程才有机会执行。

-- Patrick -帕特里克

import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

import org.junit.Test;

public class Main
{
    @Test
    public void testExecute() throws Exception
    {
        int threadCount = 20;
        final CountDownLatch threadsCompleteLatch = new CountDownLatch( threadCount );

        Map<String, Elem> saldos = new ConcurrentHashMap<>( threadCount, 0.9f, 1 );
        AtomicInteger counter = new AtomicInteger( 0 );
        Elem element = new Elem();
        saldos.put( "saldo", element );

        ExecutorService exec = Executors.newFixedThreadPool( threadCount );

        try
        {
            for ( int i = 0; i < threadCount; ++i )
            {
                exec.execute( new Sum( threadsCompleteLatch, counter, saldos ) );
            }

            threadsCompleteLatch.await();
            exec.shutdown();

            System.out.println( "got elem: " + saldos.get( "saldo" ) + " counter: " + counter );
            System.out.println( "resulting element: " + element );
        }
        catch ( Exception ex )
        {
            exec.shutdownNow();
            ex.printStackTrace();
        }
    }

}

class Elem
{
    private final AtomicInteger saldo = new AtomicInteger( 1000 );

    public int add( int value )
    {
        return saldo.getAndAdd( value );
    }

    int getSaldo()
    {
        return saldo.get();
    }

    @Override
    public String toString()
    {
        return "Elem{ " +
                "saldo=" + saldo.get() +
                " }";
    }
}

class Sum implements Runnable
{
    private final Random rand = new Random();

    private final CountDownLatch latch;
    private final AtomicInteger counter;
    private final Map<String, Elem> saldos;

    Sum( CountDownLatch latch, AtomicInteger counter, Map<String, Elem> saldos )
    {
        this.latch = latch;
        this.saldos = saldos;
        this.counter = counter;
        counter.incrementAndGet();
    }

    @Override
    public void run()
    {
        int randomValue = rand.nextInt( 1000 );
        Elem element = saldos.get( "saldo" );

        if ( randomValue % 2 != 0 )
        {
            randomValue = -randomValue;
        }

        int saldoLido = element.add( randomValue );
        int saldoAtual = element.getSaldo();
        System.out.println(
                "saldo lido: " + saldoLido + " somado: " + randomValue + " saldo atual: " + (saldoAtual) + " " + System.currentTimeMillis() );

        if ( counter.decrementAndGet() == 0 )
        {
            saldos.remove( "saldo" );
        }

        latch.countDown();
    }
}

Throw it all away and use a java.util.WeakHashMap. 将其全部扔掉,然后使用java.util.WeakHashMap. It already does exactly what you're looking for. 它已经完全可以满足您的需求。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何执行线程安全获取然后使用ConcurrentHashMap删除? - How can I perform a thread-safe get then remove with ConcurrentHashMap? 如何测试ConcurrentHashMap是否真的是线程安全的? - How can I test that ConcurrentHashMap is truly thread-safe? Java从ConcurrentHashMap中删除特定项 - Java Remove Specific Item From ConcurrentHashMap 如何从此ConcurrentHashMap中删除值 <String,ConcurrentHashMap<String,ArrayList> &gt; - How to remove a value from this ConcurrentHashMap<String,ConcurrentHashMap<String,ArrayList>> ColdFusion 9-我的线程正在占用内存-如何停止它? - ColdFusion 9 - My thread is holding onto memory - how can I stop it? ConcurrentHashMap 移除方法线程安全性 - ConcurrentHashMap remove method Thread Safetiness 在jdo中不再引用对象时,如何从数据库中删除对象? (n:1关系) - How to remove object from database when it's not referenced anymore in jdo? (n:1 relationship) 我是否必须将类扩展到 ConcurrentHashMap 或者我可以为 threadSafety 使用变量 ConcurrentHashMap - Do I have to extend class to ConcurrentHashMap or can I have variable ConcurrentHashMap for threadSafety 从单独的线程更新 Realm 时,如何避免“检测到不一致。项目位置无效”? - How can I avoid "Inconsistency detected. Invalid item position" when updating Realm from separate thread? 我可以将 ConcurrentHashMap 与 Integer 一起用于线程安全计数器吗? - Can I use ConcurrentHashMap with Integer for thread safe counters?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM