考虑以下代码
public class TestThreads {
public static void printListOfStrings(Collection<String> cs) {
for (String str : cs)
System.out.print(str + " by " + Thread.currentThread().getName());
System.out.println();
}
public static void main(String[] args) {
final List<String> lt1 = new ArrayList<>();
for (int i = 0; i < 5; i++)
lt1.add("string 1");
Thread thread1 = new Thread(" ONE ") {
@Override
public void run() {
printListOfStrings(lt1);
}
};
thread1.start();
final List<String> lt2 = new ArrayList<>();
for (int i = 0; i < 5; i++)
lt2.add("string 2");
Thread thread2 = new Thread(" TWO ") {
@Override
public void run() {
printListOfStrings(lt2);
}
};
thread2.start();
final List<String> lt3 = new ArrayList<>();
for (int i = 0; i < 5; i++)
lt3.add("string 1");
Thread thread3 = new Thread(" THREE ") {
@Override
public void run() {
printListOfStrings(lt3);
}
};
thread3.start();
}
}
第一次运行的代码输出:
string 1 by ONE string 1 by ONE string 1 by ONE string 1 by ONE string 2 by TWO string 1 by ONE string 1 by THREE
string 2 by TWO string 2 by TWO string 2 by TWO string 2 by TWO
第二次运行:
string 2 by TWO string 1 by THREE string 1 by ONE string 1 by THREE string 2 by TWO string 1 by THREE string 1 by ONE string 1 by THREE string 2 by TWO string 1 by THREE string 1 by ONE
string 2 by TWO string 2 by TWO
string 1 by ONE string 1 by ONE
string 1 by THREE string 1 by THREE string 1 by THREE string 1 by THREE
现在说到重点,当线程一和线程二在 printListOfStrings()
方法中同时运行 for 循环时,我没有遇到问题。但是线程三与线程 A 具有相同的字符串列表,不应允许与线程 A 一起运行。如果线程 A 在线程 C 之前启动,则应允许 A 在 C 等待它完成时执行,或者如果线程 C 是在 A 之前启动,应该允许 C 在 A 等待 C 完成时执行。我应该在我的 printListOfStrings()
方法中添加什么来实现这一点。提前致谢。
P.S:我不想在任何地方使用同步关键字,因为它没有给线程一个公平的运行机会(即线程出现的顺序)
最佳答案
您想要同步具有相同列表内容 的线程是很奇怪的(尽管列表本身不同,这使得@RajSharma 的回答不正确)。然而,这里是使用 Java-8 ConcurrentHashMap
解决问题的方法:
static ConcurrentHashMap<Collection<String>, Void> map = new ConcurrentHashMap<>();
public static void printListOfStrings(Collection<String> cs) {
map.computeIfAbsent(cs, k -> {
for (String str : cs)
System.out.print(str + " by " + Thread.currentThread().getName());
System.out.println();
return null;
});
}
其余代码相同。请注意,map
始终为空,我们从不向其添加元素。但是,当computeIfAbsent
为单个键运行时,该键将被阻止进行其他操作,但其他键可以并发操作。这里因为 lt1
和 lt3
列表是相等的并且具有相同的哈希码,所以它们的访问是同步的。
关于java - 排队线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32244941/