繁体   English   中英

Java 多线程程序NotifyListener行为

[英]Java Multithreaded Program NotifyListener Behavior

我一直在编写一个简单的程序,试图理解 Java 的多线程特性,并结合 Listeners 用作 Thread 关闭时的通知代理。 以下是正在使用的接口/类(主要从 web 中获取并稍作调整):

public interface ThreadCompleteListener {
    void notifyOfThreadComplete(final NotifyingThread thread);
}
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

public abstract class NotifyingThread extends Thread {
    private final Set<ThreadCompleteListener> listeners = new CopyOnWriteArraySet<ThreadCompleteListener>();

    public final void addListener(final ThreadCompleteListener listener) {
        listeners.add(listener);
    }

    public final void removeListener(final ThreadCompleteListener listener) {
        listeners.remove(listener);
    }

    private final void notifyListeners() {
        for (ThreadCompleteListener listener : listeners) {
            listener.notifyOfThreadComplete(this);
        }
    }

    @Override
    public final void run() {
        try {
            doRun();
        } finally {
            notifyListeners();
        }
    }
    
    
    public abstract void doRun();
}

Class InvokeThread 版本 1

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class InvokeThread implements ThreadCompleteListener{
    List<String> synList = Collections.synchronizedList(new ArrayList<String>());
    int threadNotifyCount = 0;
    String threadList = "";
    
    public static void main(String[] args) {        
        InvokeThread ma_0 = new InvokeThread();     
        ma_0.execute(args);
    }

    @Override
    public void notifyOfThreadComplete(NotifyingThread thread) {
        String _temp = threadList.substring(0, threadList.length()-1);
        threadNotifyCount++;
        if(threadNotifyCount == _temp.split(",").length) {
            Collections.sort(synList);
            System.out.println(thread.getName() + ": " + synList);
        }               
    }
    
    public String execute(String[] args) {
        
        // Start the Thread
        NotifyingThread thread1 = new NotifyingThread() {
            
            @Override
            public void doRun() {
                synchronized (this) {
//                  synList.addAll(Arrays.asList("zebra", "cow", "rabbit"));
                    threadList = this.getName() + "," + threadList;
                    synList.addAll(Arrays.asList(args[0].split(",")));
                }
                                
            }
        };
        
        thread1.addListener(this); 
        thread1.start();
        
        NotifyingThread thread2 = new NotifyingThread() {
            
            @Override
            public void doRun() {               
                synchronized (this) {
                    threadList = this.getName() + "," + threadList;
                    synList.addAll(Arrays.asList(args[idx].split(",")));
                }                               
            }
        };
        
        thread2.addListener(this);
        thread2.start();
    
        return "";
    }

}

Class InvokeThread 的版本 2

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class InvokeThread implements ThreadCompleteListener{
    List<String> synList = Collections.synchronizedList(new ArrayList<String>());
    int threadNotifyCount = 0;
    String threadList = "";
    
    public static void main(String[] args) {        
        InvokeThread ma_0 = new InvokeThread();     
        ma_0.execute(args);
    }

    @Override
    public void notifyOfThreadComplete(NotifyingThread thread) {
        String _temp = threadList.substring(0, threadList.length()-1);
        threadNotifyCount++;
        if(threadNotifyCount == _temp.split(",").length) {
            Collections.sort(synList);
            System.out.println(thread.getName() + ": " + synList);
        }               
    }
    
    public String execute(String[] args) {
        
        int argsCount = args.length;
        
        for(int idx=0;idx<argsCount;idx++) {
            NotifyingThread thread = new NotifyingThread() {
                
                @Override
                public void doRun() {               
                    synchronized (this) {
                        threadList = this.getName() + "," + threadList;
                        synList.addAll(Arrays.asList(args[1].split(",")));
                    }                               
                }
            };
            thread.addListener(this);
            thread.start();
        }   
                
        return "";
    }

}

输入 arguments:

"zebra,cow,rabbit"
"giraffe,camel,buffalo"

上面给出了给定 class InvokeThread 的两个版本。 第一个版本确实打印了字符串对象的排序列表,始终如一。 第二个版本偶尔什么也不打印。 请帮助我了解发生的情况。 TIA。

编辑 - 1(在更改代码以修复所罗门在评论部分报告的错误之后):

NotifyingThread 版本 2:

import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

public abstract class NotifyingThread extends Thread {
    private final Set<ThreadCompleteListener> listeners = new CopyOnWriteArraySet<ThreadCompleteListener>();

    public final void addListener(final ThreadCompleteListener listener) {
        listeners.add(listener);
    }

    public final void removeListener(final ThreadCompleteListener listener) {
        listeners.remove(listener);
    }

    private final void notifyListeners() {
        for (ThreadCompleteListener listener : listeners) {
            listener.notifyOfThreadComplete(this);
        }
    }
    
    private int idx;

    public NotifyingThread(int index) {
        this.idx = index;
    }

    @Override
    public final void run() {
        try {
            doRun(idx);
        } finally {
            notifyListeners();
        }
    }
    
    
    public abstract void doRun(int idx);
}

InvokeThread 2.1 版:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class InvokeThread implements ThreadCompleteListener{
    List<String> synList = Collections.synchronizedList(new ArrayList<String>());
    int threadNotifyCount = 0;
    String threadList = "";
    
    public static void main(String[] args) {        
        InvokeThread ma_0 = new InvokeThread();     
        ma_0.execute(args);
    }

    @Override
    public void notifyOfThreadComplete(NotifyingThread thread) {
        String _temp = threadList.substring(0, threadList.length()-1);
        threadNotifyCount++;
        if(threadNotifyCount == _temp.split(",").length) {
            Collections.sort(synList);
            System.out.println(thread.getName() + ": " + synList);
        }               
    }
    
    public String execute(String[] args) {
        
       int argsCount = args.length;
        
        for(int idx=0;idx<argsCount;idx++) {
            NotifyingThread thread = new NotifyingThread(idx) {
                
                @Override
                public void doRun(int idx) {                
                    synchronized (this) {
//                      synList.addAll(Arrays.asList("giraffe", "camel", "buffalo"));
                        threadList = this.getName() + "," + threadList;
                        synList.addAll(Arrays.asList(args[idx].split(",")));
                    }                               
                }
            };
            thread.addListener(this);
            thread.start();
        }           
        
        return "";
    }

}

该夹具确实修复了报告的原始问题,即此 class 的 v2 不偶尔打印列表。 但是,我想保留这个问题,以要求澄清所罗门关于不同步的评论。

以下更改(作为所罗门提示的结果)提供了夹具:

NotifyingThread 版本 2:

import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

public abstract class NotifyingThread extends Thread {
    private final Set<ThreadCompleteListener> listeners = new CopyOnWriteArraySet<ThreadCompleteListener>();

    public final void addListener(final ThreadCompleteListener listener) {
        listeners.add(listener);
    }

    public final void removeListener(final ThreadCompleteListener listener) {
        listeners.remove(listener);
    }

    private final void notifyListeners() {
        for (ThreadCompleteListener listener : listeners) {
            listener.notifyOfThreadComplete(this);
        }
    }
    
    private int idx;

    public NotifyingThread(int index) {
        this.idx = index;
    }

    @Override
    public final void run() {
        try {
            doRun(idx);
        } finally {
            notifyListeners();
        }
    }
    
    
    public abstract void doRun(int idx);
}

InvokeThread 2.1 版:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class InvokeThread implements ThreadCompleteListener{
    List<String> synList = Collections.synchronizedList(new ArrayList<String>());
    int threadNotifyCount = 0;
    String threadList = "";
    
    public static void main(String[] args) {        
        InvokeThread ma_0 = new InvokeThread();     
        ma_0.execute(args);
    }

    @Override
    public void notifyOfThreadComplete(NotifyingThread thread) {
        String _temp = threadList.substring(0, threadList.length()-1);
        threadNotifyCount++;
        if(threadNotifyCount == _temp.split(",").length) {
            Collections.sort(synList);
            System.out.println(thread.getName() + ": " + synList);
        }               
    }
    
    public String execute(String[] args) {
        
       int argsCount = args.length;
        
        for(int idx=0;idx<argsCount;idx++) {
            NotifyingThread thread = new NotifyingThread(idx) {
                
                @Override
                public void doRun(int idx) {                
                    synchronized (this) {
//                      synList.addAll(Arrays.asList("giraffe", "camel", "buffalo"));
                        threadList = this.getName() + "," + threadList;
                        synList.addAll(Arrays.asList(args[idx].split(",")));
                    }                               
                }
            };
            thread.addListener(this);
            thread.start();
        }           
        
        return "";
    }

}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM