如何避免在不同线程上仅当参数相同时调用相同的方法。

huangapple go评论82阅读模式
英文:

How do I avoid call to same method only if arguments are same, on different threads

问题

这个方法startProcess中:

private void startProcess(Long id)
		throws UnAuthorizedException, UnAuthenticatedException, InvalidRequestException {
	......

		createComponent(Long id);

	......
}

如果id相同,不应在单独的线程上再次调用createComponent方法或者startProcess本身。

英文:
private void startProcess(Long id)
		throws UnAuthorizedException, UnAuthenticatedException, InvalidRequestException {
	......

		createComponent(Long id);

	......
}

This method createComponent or the startProcess itself should not be called again on separate thread, if the id is same

答案1

得分: 0

如果您的方法需要一段时间,并且您只想在ID相同时(或任何参数的组合时)阻止并发访问,那么您需要为每个ID(或任何参数的组合)存储一个锁。

这些锁可以存储在一个 Map 中。

如果它只是一个类型为 Long 的ID,您可以直接将其用作Map的键。如果您有多个参数,请将它们与所需的equals/hashcode方法一起包装在一个自定义类中。

private Map<Long, Lock> locks = new ConcurrentHashMap<>(100);

private void startProcess(Long id) {
    Lock lock = locks.computeIfAbsent(id, id2 -> new ReentrantLock());

    lock.lock();
    try {
        System.out.println(System.currentTimeMillis() + " Starting " + id + " on thread " + Thread.currentThread().getName());
        try { Thread.sleep(2000); } catch (InterruptedException ex) { }
        System.out.println(System.currentTimeMillis() + " Done with " + id + " on thread " + Thread.currentThread().getName());
    } finally {
        lock.unlock();
        locks.remove(lock);
    }
}

调用方式如下:

new Thread(() -> startProcess(1L), "A").start();
new Thread(() -> startProcess(1L), "B").start();
new Thread(() -> startProcess(2L), "C").start();

这是可能的输出之一:

1595950202869 Starting  1 on thread A
1595950202879 Starting  2 on thread C
1595950204870 Done with 1 on thread A
1595950204870 Starting  1 on thread B
1595950204879 Done with 2 on thread C
1595950206870 Done with 1 on thread B

[编辑] 参数的自定义类示例代码:

private Map<ProcessParams, Lock> locks = new ConcurrentHashMap<>(100);

private void startProcess(long id, String name) {
    Lock lock = locks.computeIfAbsent(new ProcessParams(id, name), id2 -> new ReentrantLock());

    lock.lock();
    try {
        System.out.println(System.currentTimeMillis() + " Starting " + name + " on thread " + Thread.currentThread().getName());
        try { Thread.sleep(2000); } catch (InterruptedException ex) { }
        System.out.println(System.currentTimeMillis() + " Done with " + name + " on thread " + Thread.currentThread().getName());
    } finally {
        lock.unlock();
        locks.remove(lock);
    }
}

public static class ProcessParams {
    private final long   id;
    private final String name;

    public ProcessParams(long id, String name) {
        this.id = id;
        this.name = Objects.requireNonNull(name, "name");
    }

    @Override
    public boolean equals(Object o) {
        if (this == o)
            return true;

        if (!(o instanceof ProcessParams))
            return false;

        ProcessParams other = (ProcessParams)o;
        return id == other.id && name.equals(other.name);
    }

    @Override
    public int hashCode() {
        int hashCode = 0x811C9DC5;
        hashCode = 0x01000193 * (hashCode ^ Long.hashCode(id));
        hashCode = 0x01000193 * (hashCode ^ name.hashCode());
        return hashCode;
    }
}
英文:

If your method takes time and you want to block concurrent access only when the ID is the same (or any combination of parameters) then you need to store a lock for every ID (or any combination of parameters).

These locks can be stored in a Map.

If it's just an ID of type Long you can use it directly as the Map's key. If you have multiple parameters, wrap them in a custom class along with the required equals/hashcode methods.

private Map&lt;Long, Lock&gt; locks = new ConcurrentHashMap&lt;&gt;(100);
private void startProcess(Long id) {
Lock lock = locks.computeIfAbsent(id, id2 -&gt; new ReentrantLock());
lock.lock();
try {
System.out.println(System.currentTimeMillis() + &quot; Starting  &quot; + id + &quot; on thread &quot; + Thread.currentThread().getName());
try { Thread.sleep(2000); } catch (InterruptedException ex) { }
System.out.println(System.currentTimeMillis() + &quot; Done with &quot; + id + &quot; on thread &quot; + Thread.currentThread().getName());
} finally {
lock.unlock();
locks.remove(lock);
}
}

Called with:

new Thread(() -&gt; startProcess(1L), &quot;A&quot;).start();
new Thread(() -&gt; startProcess(1L), &quot;B&quot;).start();
new Thread(() -&gt; startProcess(2L), &quot;C&quot;).start();

this is one possible output:

1595950202869 Starting  1 on thread A
1595950202879 Starting  2 on thread C
1595950204870 Done with 1 on thread A
1595950204870 Starting  1 on thread B
1595950204879 Done with 2 on thread C
1595950206870 Done with 1 on thread B

[Edit] Sample code for custom class for parameters:

private Map&lt;ProcessParams, Lock&gt; locks = new ConcurrentHashMap&lt;&gt;(100);
private void startProcess(long id, String name) {
Lock lock = locks.computeIfAbsent(new ProcessParams(id, name), id2 -&gt; new ReentrantLock());
lock.lock();
try {
System.out.println(System.currentTimeMillis() + &quot; Starting  &quot; + name + &quot; on thread &quot; + Thread.currentThread().getName());
try { Thread.sleep(2000); } catch (InterruptedException ex) { }
System.out.println(System.currentTimeMillis() + &quot; Done with &quot; + name + &quot; on thread &quot; + Thread.currentThread().getName());
} finally {
lock.unlock();
locks.remove(lock);
}
}
public static class ProcessParams {
private final long   id;
private final String name;
public ProcessParams(long id, String name) {
this.id = id;
this.name = Objects.requireNonNull(name, &quot;name&quot;);
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof ProcessParams))
return false;
ProcessParams other = (ProcessParams)o;
return id == other.id &amp;&amp; name.equals(other.name);
}
@Override
public int hashCode() {
int hashCode = 0x811C9DC5;
hashCode = 0x01000193 * (hashCode ^ Long.hashCode(id));
hashCode = 0x01000193 * (hashCode ^ name.hashCode());
return hashCode;
}
}

huangapple
  • 本文由 发表于 2020年7月28日 23:13:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/63137416.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定