• 当static遇到类继承。。也许你会懵。。


    有如下代码:

    public class BaseService {
        protected static ExecutorService executorService = Executors.newFixedThreadPool(1);
    }
    
    @Slf4j
    public class Service1 extends BaseService {
        public void foo() {
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(1000 * 10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    log.info("ok");
                }
            });
        }
    }
    @Slf4j
    public class Service2 extends BaseService {
    
        public void foo() {
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(1000 * 10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    log.info("ok");
                }
            });
        }
    }
    
    
    public class TestMain {
        public static void main(String[] args) {
            Service1 service1 = new Service1();
            service1.foo();
    
            Service2 service2=new Service2();
            service2.foo();
        }
    }

    如下是程序输出。可以看到出现了线程排队(间隔了10秒)。 为什么?首先,要正确理解面向对象的继承特性,派生类继承的是基类的非静态成员。 也就是说,静态的executorService是不会被继承的;  其次,再说static,由static修饰的静态成员,是容器启动过程中在初始化所在类时,就被实例化并装载到内存里了。在不被干预的情况下,其生命周期等同于整个容器服务的生命周期。我们知道,static成员直接用“类.静态成员”就可以访问。 总结来说,就像访问一些util类的工具方法一样,Service1里和Service2里访问的相当于是BaseService.executorService,只不过因为executorService在这2个派生类里是可见的,所以不需要显式加”BaseService.“了。 两个service共用的是同一个只有1个线程的线程池,那么,自然就出现线程等待了。

    18:54:55.465 [pool-1-thread-1] INFO stacktrace.service.Service1 - ok
    18:55:05.467 [pool-1-thread-1] INFO stacktrace.service.Service2 - ok

    那么,把BaseService里的executorService改为非静态呢。根据面向对象的继承特性,Service1、Service2各持有一个executorService对象,自然不存在线程排队的情况。再执行main方法的结果是下面这样子的。

    18:54:55.465 [pool-1-thread-1] INFO stacktrace.service.Service1 - ok
    18:54:55.465 [pool-2-thread-1] INFO stacktrace.service.Service2 - ok

    后记:

    线程池这样的对象一定要定义成静态的。否则,每new一个对象,就new一个线程池对象,将会糟糕透顶。


    附记:

    查看容器里当前线程数,使用Thread类的静态方法getAllStackTraces()

     代码: 

    @Slf4j
    public class TestMain {
        public static void main(String[] args) {
            int size = Thread.getAllStackTraces().keySet().size();
            log.info("size={}", size);
            Iterator<Thread> iterator = Thread.getAllStackTraces().keySet().iterator();
            log.info("----------");
            while (iterator.hasNext()) {
                Thread thread = iterator.next();
                StackTraceElement[] stackTraces = thread.getStackTrace();
                log.info("-->{}, stackTrace.length={},state={}", thread.getName(),
                        stackTraces.length,thread.getState());
    //            for (StackTraceElement element : stackTraces) {
    //                log.info(element.toString());
    //            }
            }
        }
    }

    运行结果:

    21:12:36.322 [main] INFO stacktrace.service.TestMain - size=8
    21:12:36.340 [main] INFO stacktrace.service.TestMain - ----------
    21:12:36.341 [main] INFO stacktrace.service.TestMain - -->main, stackTrace.length=2,瞬间状态=RUNNABLE
    21:12:36.342 [main] INFO stacktrace.service.TestMain - -->Attach Listener, stackTrace.length=0,瞬间状态=RUNNABLE
    21:12:36.343 [main] INFO stacktrace.service.TestMain - -->Signal Dispatcher, stackTrace.length=0,瞬间状态=RUNNABLE
    21:12:36.343 [main] INFO stacktrace.service.TestMain - -->pool-1-thread-1, stackTrace.length=5,瞬间状态=TIMED_WAITING
    21:12:36.344 [main] INFO stacktrace.service.TestMain - -->Reference Handler, stackTrace.length=3,瞬间状态=WAITING
    21:12:36.345 [main] INFO stacktrace.service.TestMain - -->pool-2-thread-1, stackTrace.length=5,瞬间状态=TIMED_WAITING
    21:12:36.345 [main] INFO stacktrace.service.TestMain - -->Monitor Ctrl-Break, stackTrace.length=12,瞬间状态=RUNNABLE
    21:12:36.346 [main] INFO stacktrace.service.TestMain - -->Finalizer, stackTrace.length=4,瞬间状态=WAITING
  • 相关阅读:
    linux 服务器---FastDFS分布式文件服务器配置
    JFinal getModel方法(从页面表单中获取Model对象)+数据库存储问题
    实现Callable接口。带返回值的线程
    Spring 自动化装配Bean
    Spring--基于代理类ProxyFactoryBean的AOP实现
    Jfinal中的validator理解/详解
    Jfinal中的文件上传
    HotSpot学习(二):虚拟机的启动过程源码解析
    HotSpot学习(一):编译、启动与调试
    Netty的对象池
  • 原文地址:https://www.cnblogs.com/buguge/p/14287346.html
Copyright © 2020-2023  润新知