gpt4 book ai didi

java - 以同步、线程安全的方式加载共享资源

转载 作者:行者123 更新时间:2023-12-01 21:52:03 25 4
gpt4 key购买 nike

问题

我只想加载共享资源一次并将它们保留在内存中。目前,我使用同步方法进行加载,并使用 HashMap 将加载的资源保留在内存中。

问题

问题1:

是否有更好的方法使用标准 Java 方法来实现此目的?

问题2:

下面的代码生成 6 个线程,其中 3 个访问资源 1,另外 3 个访问资源 2。日志输出如下:

Get resource id: 1
Load resource id: 1
Counter: 1
Get resource id: 2
Thread Thread[Thread-0,5,main], loaded resource id: 1
Load resource id: 2
Counter: 2
Thread Thread[Thread-5,5,main], loaded resource id: 2
Get resource id: 2
Thread Thread[Thread-4,5,main], loaded resource id: 2
Get resource id: 2
Thread Thread[Thread-3,5,main], loaded resource id: 2
Get resource id: 1
Get resource id: 1
Thread Thread[Thread-2,5,main], loaded resource id: 1
Thread Thread[Thread-1,5,main], loaded resource id: 1

问题是加载资源 id 1 的线程会被阻塞,直到加载资源 id 2 的线程完成为止。即使资源 id 2 仍在加载,如何才能让资源 id 1 的线程继续运行?

代码

示例代码如下:

import java.util.HashMap;
import java.util.Map;

public class SharedResourceLoader {

/**
* Resource loading counter, shows how often the loading is invoked.
*/
public static int loadCounter = 0;

/**
* Map of type <Resource Id, Resource> for keeping loaded resources in memory
*/
public static Map<Integer,Resource> resourceMap = new HashMap<>();

/**
* Get a resource by Id
* @param id
* @return
*/
public static Resource getResource( int resourceId) {

Resource resource = resourceMap.get( resourceId);

if( resource == null) {
resource = loadResource( resourceId);
}

return resource;
}

/**
* Get a resource by Id synchronized. If it isn't found, load it.
* @param resourceId
* @return
*/
public static synchronized Resource loadResource( int resourceId) {

System.out.println("Get resource id: " + resourceId);

Resource resource = resourceMap.get( resourceId);

if( resource == null) {

System.out.println("Load resource id: " + resourceId);

// load resource
resource = new Resource( resourceId);
resource.load();

// keep resource in memory
resourceMap.put( resourceId, resource);

// just a counter to see how often this method is accessed
loadCounter++;
System.out.println("Counter: " + loadCounter);
}

return resource;

}

/**
* Start a thread that accesses the resource with the given id
* @param resourceId
*/
public static void spawnThread( int resourceId) {

Thread thread = new Thread( new Runnable() {
@Override
public void run() {

Resource resource = getResource(resourceId);

System.out.println( "Thread " + Thread.currentThread() + ", loaded resource id: " + resource.id);


}
});
thread.start();

}

public static class Resource {

int id;

public Resource( int id) {
this.id = id;
}

public void load() {

// dummy sleep, e. g. resource loading happens here
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
}
}
}

public static void main(String[] args) {

spawnThread( 1);
spawnThread( 1);
spawnThread( 1);

spawnThread( 2);
spawnThread( 2);
spawnThread( 2);

}

}

最佳答案

看看java.util.concurrentjava.util.concurrent.atomic包。

如果我是你,我会使用ConcurrentHashMap:

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

public class SharedResourceLoader {

/**
* Resource loading counter, shows how often the loading is invoked.
*/
private static final AtomicInteger loadCounter = new AtomicInteger();

/**
* Map of type <Resource Id, Resource> for keeping loaded resources in memory
*/
public static ConcurrentMap<Integer, Resource> resourceMap = new ConcurrentHashMap<>();

/**
* Get a resource by Id
*
* @param resourceId
* @return
*/
public static Resource getResource(int resourceId) {

Resource resource = resourceMap.get(resourceId);

if (resource == null) {
resource = loadResource(resourceId);
}

return resource;
}

/**
* Get a resource by Id synchronized. If it isn't found, load it.
*
* @param resourceId
* @return
*/
public static Resource loadResource(int resourceId) {

System.out.println("Get resource id: " + resourceId);

Resource resource = resourceMap.get(resourceId);

if (resource == null) {

System.out.println("Load resource id: " + resourceId);

// load resource
final Resource r = resourceMap.putIfAbsent(resourceId, resource = new Resource(resourceId));

// important!
if (r != null) {
resource = r;
}

if (resource.load()) {
// just a counter to see how often this method is accessed
loadCounter.getAndIncrement();
}

System.out.println("Counter: " + loadCounter);
}

return resource;

}

public static int loadCounter() {
return loadCounter.get();
}

/**
* Start a thread that accesses the resource with the given id
*
* @param resourceId
*/
public static void spawnThread(int resourceId) {

Thread thread = new Thread(new Runnable() {
@Override
public void run() {

Resource resource = getResource(resourceId);

System.out.println("Thread " + Thread.currentThread() + ", loaded resource id: " + resource.id);


}
});
thread.start();

}

public static class Resource {

final int id;
final AtomicBoolean loaded = new AtomicBoolean(false);

public Resource(int id) {
this.id = id;
}

public boolean load() {
if (loaded.compareAndSet(false, true)) {
// dummy sleep, e. g. resource loading happens here
try {
Thread.sleep(5000);
} catch (InterruptedException ignored) {
}
return true;
}
return false;
}
}

public static void main(String[] args) {

spawnThread(1);
spawnThread(1);
spawnThread(1);

spawnThread(2);
spawnThread(2);
spawnThread(2);

}

}

输出:

Get resource id: 1
Get resource id: 2
Get resource id: 2
Get resource id: 2
Get resource id: 1
Get resource id: 1
Load resource id: 1
Load resource id: 2
Load resource id: 2
Load resource id: 2
Load resource id: 1
Load resource id: 1
Counter: 0
Counter: 0
Counter: 0
Counter: 0
Thread Thread[Thread-5,5,main], loaded resource id: 2
Thread Thread[Thread-4,5,main], loaded resource id: 2
Thread Thread[Thread-1,5,main], loaded resource id: 1
Thread Thread[Thread-2,5,main], loaded resource id: 1
Counter: 1
Thread Thread[Thread-3,5,main], loaded resource id: 2
Counter: 2
Thread Thread[Thread-0,5,main], loaded resource id: 1

关于java - 以同步、线程安全的方式加载共享资源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35056071/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com