java-ee - JAVA的异步线程与同步线程问题.

 手机用户2502869943 发布于 2022-10-27 16:16
    public static void main(String[] args) {
        int threadCount = 1000; // 线程数量(1000)
        CountDownLatch countDownLatch = new CountDownLatch(threadCount);
        List list = new ArrayList();
        
        MyThreadTest myThreadTest = new MyThreadTest(list);
       
        MySync mySync = MySync.getMySync(myThreadTest,countDownLatch);
        // mySync = new MySync(myThreadTest,countDownLatch);  // 为什么放开这段代码,会连 System.out.println("========:"+list.size()); 都不会执行了?
        
        try {
        for(int i =0;i list;
    
    private int i = 0;
    
    public MyThreadTest(List list){
        this.list = list;
    }
    
    @Override
    public void run() {
        i++;
        list.add(new Object());
        System.out.println(i);
    }
}

class MySync{

    private static CountDownLatch countDownLatch;
    private static Runnable runn;
    
    public MySync(){}
    
    @SuppressWarnings("static-access")
       public MySync(Runnable runn,CountDownLatch countDownLatch){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(MySync.class);
        enhancer.setCallback(new MethodInterceptorImpl());

        MySync mySync = (MySync)enhancer.create();
        mySync.countDownLatch = countDownLatch;
        mySync.runn = runn;
    }
    
    @SuppressWarnings("static-access")
    public static MySync getMySync(Runnable runn,CountDownLatch countDownLatch){
         Enhancer enhancer = new Enhancer();
         enhancer.setSuperclass(MySync.class);
         enhancer.setCallback(new MethodInterceptorImpl());
         
         MySync mySync = (MySync)enhancer.create();
         mySync.countDownLatch = countDownLatch;
         mySync.runn = runn;
         return mySync;
    }
    
    public void run() throws InterruptedException {
            MyThreadPool.execute(runn);
    }
    
    private static class MethodInterceptorImpl implements MethodInterceptor{

        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            Object result = proxy.invokeSuper(obj, args);
            if("public void MySync.run() throws java.lang.InterruptedException".equals(method.toString())){
                countDownLatch.countDown(); // 完成一个子线程,减少一个计数
                return result;
            }
            return result;
        }
        
    }
}

class MyThreadPool {

    private static ExecutorService pool = null;
    
    @SuppressWarnings("unchecked")
    public static  T submit(Runnable runn){
        T result = null;
        if (pool == null) {
            pool = Executors.newCachedThreadPool();
        }
        try {
            Future future = pool.submit(runn);
            if(future.isDone()==true){
                result = (T) future.get();
            }
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    
    public static void execute(Runnable runn){
        if (pool == null) {
            pool = Executors.newCachedThreadPool();
        }
        try {
            pool.execute(runn);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

System.out.println("========:"+list.size()); 使用计数来进行了同步,这段代码不应该是最后才会输出的吗?测试结果是不确定什么时候输出.
如果放开注释的那段代码,为什么连System.out.println("========:"+list.size()); 都不输出了?这是什么原因造成的?(不知道这段代码还有什么BUG,请各位大神指导)

2 个回答
  • 首先,我想吐槽一下,代码确实很乱,看了老半天。

    总结一下,你这里主要使用的是 CountDownLatch 和 CGLIB 字节码增强技术。

    CountDownLatch 的主要功能是它允许一个或多个线程一直等待,直到其他线程的操作执行完后再执行。但是因为每个线程在执行完要在 finally 块调用 countdown() 方法,所以想利用 CGLIB 在线程执行完之后,自动调用 coundown()方法。但问题也就出现在这里:

    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        Object result = proxy.invokeSuper(obj, args); // 这里实际上是非阻塞的。
        if("public void MySync.run() throws java.lang.InterruptedException".equals(method.toString())){
            countDownLatch.countDown(); // 完成一个子线程,减少一个计数
            return result;
        }
        return result;
    }
    2022-10-28 13:55 回答
  • 先回答楼主的问题

    1. CGLIB 字节码增强是对的你MySync的方法进行增强,你文中的步骤是先执行MySync.run(),然后再把线程丢入线程池,所以在执行MySync.run()的时候就已经执行countDownLatch.countDown()了,所以这里会出现一个情况是,countDownLatch.await()的时候线程池里面还有茫茫多的线程在运行,所以listsize是随机的

    2. 你直接放开mySync = new MySync(myThreadTest,countDownLatch)这段代码以后,构造器直接构造MySync是没有经过CGLIB加强的类,MySync mySync = (MySync) enhancer.create();mySync.countDownLatch = countDownLatch;mySync.runn = runn;你在构造器里面增强的这个MySync,随着构造方法的结束,就被垃圾回收器回收了

    再来说说楼主程序的问题

    1. if("public void MySync.run() throws java.lang.InterruptedException".equals(method.toString())这一段代码,可以用method.getName()来比较

    2. MyThreadTest这个线程类,在run()中执行i++不是线程安全的,并且因为list也不是先后才能安全的,所以list.add()也会出现线程竞争问题

    2022-10-28 13:58 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有