Java, создайте кэш многоразовых небезопасных объектов - PullRequest
0 голосов
/ 21 января 2020

Иногда в java У меня есть объекты, которые являются небезопасными и дорогими в создании. Я хотел бы создать кеш этих объектов, чтобы мне не нужно было их заново создавать, но он также должен предотвращать одновременный доступ к одному и тому же объекту.

Например, у меня может быть DateFormat и его создание. это слишком дорого, но я не могу поделиться ни одной DateFormat. Ради аргументов предположим, что я не могу использовать потокобезопасный DateFormat.

. Что было бы фантастически c, так это создать такой кеш:

Cache<DateFormat> cache = new Cache(() -> dateFormatCreator());
// and now make use of a dateFormat that might be created for this call 
// or it might be an existing one from the cache.
cache.withExclusiveAccessToObject(dateFormat -> {
   // use the dateFormat here, it is not in use by any other thread at the same time.
   // new dateFormats can be created on the fly as needed.
});

Я должен был также упомянуть, что ThreadLocal не идеален, так как я не могу гарантировать, что потоки будут использоваться повторно.

1 Ответ

0 голосов
/ 21 января 2020

Я считаю, что есть два пути, которые вы можете go:

Опция 1

Поддерживать объект для потока

Это может работать, если вы обращаетесь к дорогостоящему объекту из ограниченного четко определенного набора потоков (читай, используя пул потоков и не создавая потоки каждый раз, что в любом случае происходит во многих приложениях).

В этом случае вы можно использовать ThreadLocal. Поскольку в одном потоке все должно быть последовательным, вы можете хранить небезопасные для потока объекты в локальном потоке.

Вы можете думать о ThreadLocal как о карте, в которой для каждого потока поддерживается выделенный экземпляр дорогого объекта.

Опция 2

Совместно использовать один (или N в общем) объект между M потоками, чтобы N

Я не знаю о готовом решении для этого, после того, как все ваши объекты вы хотите сохранить, но в целом довольно легко обернуть вашу собственную реализацию, которая обеспечит своего рода блокировку / синхронизированный доступ к объекты для ваших типов объектов.

Диапазон идей для реализации может варьироваться. В качестве идеи: вы можете обернуть реальный объект сгенерированным прокси во время выполнения / времени сборки, что делает его эффективно поточно-ориентированным:

public interface IMyObject {
    void inc();
    void dec();
}

// this is an object that you would like to make thread safe
public class MyActualObject implements IMyObject {
    private int counter = 0;
    void inc() {counter++;}
    void dec() {counter--;}
}

public class MyThreadSafeProxy implements IMyObject {

    private IMyObject realObject;

    public MyThreadSafeProxy(IMyObject realObject) {
        this.realObject = realObject;
    }

    @Override
    public synchronized void inc() {
       realObject.inc();
    }

    @Override 
    public syncrhonized void dec() {
       realObject.dec();
    }
}

Вместо хранения MyObject -s вы можете обернуть их в MyThreadSafeProxy

Возможно также создать такой прокси автоматически: см. cglib framework или Dynami c Proxy (java .lang.Proxy class)

Исходя из моего опыта, вариант 1 предпочтителен, если только объекты, с которыми вы работаете, не слишком дороги, поэтому, если в пуле N потоков, вы не сможете реально поддерживать N объектов в памяти.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...