Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 当不再有线程持有某个对象时,如何从ConcurrentHashMap中删除项目?_Java_Multithreading_Concurrency_Locking - Fatal编程技术网

Java 当不再有线程持有某个对象时,如何从ConcurrentHashMap中删除项目?

Java 当不再有线程持有某个对象时,如何从ConcurrentHashMap中删除项目?,java,multithreading,concurrency,locking,Java,Multithreading,Concurrency,Locking,假设我有一个临时集合(ConcurrentHashMap)来保存某个对象的引用,例如HttpSession。当至少有一个线程正在使用一个会话时(在请求时),它不能被删除。但是,当没有更多线程同时使用会话时,应该删除该会话以释放内存。我尝试实现一个类似的示例,但得到了一个NullPointerException。我做错了什么( 类元素{ //AtomicInteger saldo=新的AtomicInteger(1000); 整数saldo=1000; } 类Sum实现可运行{ 萨尔多斯地图; 原

假设我有一个临时集合(ConcurrentHashMap)来保存某个对象的引用,例如HttpSession。当至少有一个线程正在使用一个会话时(在请求时),它不能被删除。但是,当没有更多线程同时使用会话时,应该删除该会话以释放内存。我尝试实现一个类似的示例,但得到了一个NullPointerException。我做错了什么(

类元素{
//AtomicInteger saldo=新的AtomicInteger(1000);
整数saldo=1000;
}
类Sum实现可运行{
萨尔多斯地图;
原子整数n;
公共和(映射saldos,原子整数n){
this.saldos=saldos;
这个,n=n;
}
@凌驾
公开募捐{
Random rand=新的Random();
int r=兰特·耐克斯汀(1000);
Elem e=this.saldos.get(“saldo”);
//此处发生空指针异常!
已同步(e){
这个.n.incrementAndGet();
如果(r%2==0){
整数saldoLido=e.saldo;
e、 saldo+=r;
整数saldoAtual=e.saldo;
System.out.println(“莎尔多丽都:+saldoLido+”索马多:+r
+“莎尔多·阿图尔:+(莎尔多·阿图尔)+”
+System.currentTimeMillis());
}否则{
整数saldoLido=e.saldo;
e、 saldo-=r;
整数saldoAtual=e.saldo;
System.out.println(“saldo lido:+saldoLido+”subtraído:”
+r+“莎尔多舞曲:+(莎尔多舞曲)+”
+System.currentTimeMillis());
}
如果(此.n.decrementAndGet()==0)
这个.saldos.remove(“saldo”);
}
}
}
公共班机{
公共静态void main(字符串[]args)引发异常{
Map saldos=新的ConcurrentHashMap(20,0.9f,1);
AtomicInteger n=新的AtomicInteger(0);
saldos.put(“saldo”,newelem());
ExecutorService exec=Executors.newFixedThreadPool(20);
试一试{
对于(int i=0;i<20;++i)
exec.execute(新的Sum(saldos,n));
exec.shutdown();
而(!exec.isTerminated()){
System.out.println(“got元素:+saldos.get(“saldo”)+”+n);
}捕获(例外情况除外){
exec.shutdownNow();
例如printStackTrace();
}
}
}

扔掉它,使用一个
java.util.WeakHashMap。
它已经完全满足了您的需求。

扔掉它,使用一个
java.util.WeakHashMap。
它已经满足了您的需求。

我为您准备了一个工作示例,可以帮助您解决问题。我做了一个junit测试使其易于在您喜爱的IDE或其他地方运行

有几点需要注意

添加了一个倒计时闩锁,这样所有线程都将在executor服务关闭并打印结果之前完成

Elem使用原子整数,因此不再需要同步块

对代码最重要的修复是增加Sum类构造函数中的计数器,这样直到每个线程都有机会进行处理时,元素才从映射中删除。否则,一个线程可能会一直运行,并在其他线程有机会执行之前删除元素

--帕特里克

import java.util.Map;
导入java.util.Random;
导入java.util.concurrent.ConcurrentHashMap;
导入java.util.concurrent.CountDownLatch;
导入java.util.concurrent.ExecutorService;
导入java.util.concurrent.Executors;
导入java.util.concurrent.AtomicInteger;
导入org.junit.Test;
公共班机
{
@试验
public void testExecute()引发异常
{
int threadCount=20;
最终CountDownLatch threadsCompleteLatch=新的CountDownLatch(threadCount);
Map saldos=新的ConcurrentHashMap(线程数,0.9f,1);
AtomicInteger计数器=新的AtomicInteger(0);
元素=新元素();
saldos.put(“saldo”,元素);
ExecutorService exec=Executors.newFixedThreadPool(线程计数);
尝试
{
对于(int i=0;i    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();
        }

    }

    }
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();
    }
}