Java 如何确保一行代码对每个线程只运行一次?
我有几个线程同时运行,每当每个线程启动时,我希望每个线程都从stringarraylist中获取一个项目,并保留该特定的唯一项目,直到它完成。实现这一点的好方法是什么?在线程中的run方法中,我考虑了字符串uniqueItem=itemList.get(k);和k++之后,但线程将一遍又一遍地运行该特定行,下次再次运行时,它将保留一个不同的唯一项。有没有办法让每个线程只获取一个项目一次,下一个线程获取可用的项目,依此类推,并保留该项目Java 如何确保一行代码对每个线程只运行一次?,java,multithreading,threadpool,executorservice,Java,Multithreading,Threadpool,Executorservice,我有几个线程同时运行,每当每个线程启动时,我希望每个线程都从stringarraylist中获取一个项目,并保留该特定的唯一项目,直到它完成。实现这一点的好方法是什么?在线程中的run方法中,我考虑了字符串uniqueItem=itemList.get(k);和k++之后,但线程将一遍又一遍地运行该特定行,下次再次运行时,它将保留一个不同的唯一项。有没有办法让每个线程只获取一个项目一次,下一个线程获取可用的项目,依此类推,并保留该项目 ItemHolder thread = new Item
ItemHolder thread = new ItemHolder();
private ArrayList<String> itemList = new ArrayList<String>(); //Contains 4 Strings (e.g. Apple, Orange, Watermelon, Pear)
int k = 0;
ExecutorService executor = Executors.newFixedThreadPool(4); //E.g. run 4 Threads
executor.execute(thread);
class ItemHolder extends Thread{
public void run(){
String uniqueItem = itemList.get(k); //Would like the first thread to grab the first index item, 0, and hold onto it until it finishes. But other thread that runs the same, I would like it to have index item, 1, and hold onto that, and the other thread to have whatever is available and so on.
k++; //This would be a problem
}
}
ItemHolder线程=新的ItemHolder();
private ArrayList itemList=new ArrayList()//包含4个字符串(例如苹果、橘子、西瓜、梨)
int k=0;
ExecutorService executor=Executors.newFixedThreadPool(4)//例如,运行4个线程
执行器。执行(线程);
类ItemHolder扩展线程{
公开募捐{
String uniqueItem=itemList.get(k);//希望第一个线程获取第一个索引项0,并一直保持到它完成。但是其他运行相同的线程,我希望它具有索引项1,并保持该索引项,另一个线程具有任何可用的索引项,依此类推。
k++;//这将是一个问题
}
}
您希望避免两个线程同时执行get()然后同时递增k的情况。要实现这一点,必须确保每个线程都以原子方式递增k。你可以用它来做这件事
private ArrayList<String> itemList = new ArrayList<String>();
AtomicInteger a = new AtomicInteger();
ExecutorService executor = Executors.newFixedThreadPool(4);
for (int i=0; i<itemList.size(); i++) { // I assume itemList will not be modified
ItemHolder thread = new ItemHolder();
executor.execute(thread);
}
class ItemHolder extends Thread{
public void run(){
int k = a.getAndAdd(1);
String uniqueItem = itemList.get(k);
// Some lengthy processing might occur here...
}
}
private ArrayList itemList=new ArrayList();
AtomicInteger a=新的AtomicInteger();
ExecutorService executor=Executors.newFixedThreadPool(4);
对于(int i=0;i您正在使用ExecutorService
。这意味着您不需要传递线程
实例,但可运行
就足够了
话虽如此,您将创建Runnable
实例,并以某种循环方式将它们传递给ExecutorService
。您可以在本地字段中维护每个Runnable的状态,您可以在其中存储运行该Runnable实例的索引
如果未设置runnable的状态,则需要进行检查,然后将其设置为runnable将操作的元素。如果已设置状态,则不执行任何操作。您应该使用java.util.concurrent.BlockingQueue
,因为ArrayList
不是线程安全的
示例代码:
public class ItemHolderDemo {
public static void main(String[] args) {
BlockingQueue<String> queue = new LinkedBlockingQueue<>();
queue.add("a");
queue.add("b");
Runnable thread = new ItemHolder(queue);
ExecutorService executor = Executors.newFixedThreadPool(4); //E.g. run 4 Threads
executor.execute(thread);
}
static class ItemHolder extends Thread {
BlockingQueue<String> queue;
public ItemHolder(BlockingQueue<String> queue) {
this.queue = queue;
}
public void run() {
String uniqueItem = null;
// use while loop in case there is an interruption
while (uniqueItem == null) {
try {
// use queue.poll() with break statements if you want a timed wait
uniqueItem = queue.take();
} catch (InterruptedException e) {
}
}
// got item
System.out.println(uniqueItem);
}
}
}
公共类ItemHolderDemo{
公共静态void main(字符串[]args){
BlockingQueue=新建LinkedBlockingQueue();
队列。添加(“a”);
添加(“b”);
Runnable线程=新的ItemHolder(队列);
ExecutorService executor=Executors.newFixedThreadPool(4);//例如,运行4个线程
执行器。执行(线程);
}
静态类ItemHolder扩展线程{
阻塞队列;
公共项目持有者(阻止队列){
this.queue=队列;
}
公开募捐{
字符串uniqueItem=null;
//使用while循环以防中断
while(uniqueItem==null){
试一试{
//如果需要定时等待,请将queue.poll()与break语句一起使用
uniqueItem=queue.take();
}捕捉(中断异常e){
}
}
//得到项目
系统输出打印项次(唯一项);
}
}
}
是k
类成员吗?听起来你需要k
才是线程安全的,所以你应该使用AtomicInteger
。参见[Jon Skeet的答案]()