多线程使用中的一些好习惯

本文主要介绍个人在多线程使用和调优中总结一些线程使用比较好的习惯,方便大家在线程出现问题时排查,好习惯是高效率的基础

几个习惯分别为设置线程名处理interrupt、使用ThreadLocal

其他下次再写吧

 

1、设置线程名

使用过VisualVM或其他java自带工具或是thread dump的朋友都能体会到如果线程没有设置名称,要进行性能问题排查和调优那是相当头大的一件事,下面先贴一张VisualVM的Threads运行图


上图中几个紫色的线程是自定义线程,可以看出前三个线程被手动命名过,后三个线程为自动命令。在这个图中还不是很容易看出差别,因为它只是个简单的main函数,线程个数也有限。但如果对于一个较大的软件或是web程序,线程数成百上千,自动的命名方法你还能识别出哪个线程是你自己的吗???

下面介绍几种命名线程的方法,主要有三种:

(1) new Thread("threadName")

(2) thread.setName("threadName")

(3)子类的构造函数中super(threadName),其实跟第一种一样

 

具体代码可以查看本文最后源码,可以运行其中的setThreadNameExam()函数;

 

2、处理interrupt

通常将较耗时或较复杂操作单独放在线程中,所以线程中极有可能出现大循环或较耗时,如果这时候突然中断,默认线程退出是不会有其他响应的,对于线程中断有三种方法可以处理:

(1) 使用

if (Thread.interrupted()) {
	doSomeThing();
}

处理

(2) 捕获异常

try {
	doXXX();
} catch(InterruptedException e) {
	// handle Exception
} catch(Exception e) {
	// handle Exception
}

(3) 抛出异常

public void foo() throws InterruptedException {
	if(Thread.interrupted()) {
		throw new InterruptedException();
	}
}

具体使用可以查看本文最后的源码,可以运行其中的 threadInterruptExam();

 

3、使用ThreadLocal

ThreadLocal

 

本文示例代码如下

    private static int       count1InInterruptExam = 0, count2InInterruptExam = 0;

    public static void main(String[] args) {
        // setThreadNameExam();
        threadInterruptExam();
    }

    public static void setThreadNameExam() {
        /** 未设置线程名 **/
        nonNamedThread();

        /** 在new thread时设置线程名,有多种构造函数,可以参考Thread java源代码中名为init的私有方法 **/
        namedThread1();

        /** 通过Thread的setName方法设置线程名 **/
        namedThread2();

        /** 继承自Thread的子类,可以在构造函数中使用super(name)设置线程名 **/
        namedThread3();
    }

    public static void nonNamedThread() {
        for (int i = 0; i < 3; i++) {
            Thread nonNamedThread = new Thread() {

                public void run() {
                    threadLogic();
                }
            };
            nonNamedThread.start();
        }
    }

    public static void namedThread1() {
        Thread namedThread1 = new Thread("namedThread1 named when new thread") {

            public void run() {
                threadLogic();
            }
        };
        namedThread1.start();

    }

    public static void namedThread2() {
        Thread namedThread2 = new Thread() {

            public void run() {
                threadLogic();
            }
        };
        namedThread2.setName("namedThread2 named  by Thread.setName");
        namedThread2.start();
    }

    public static void namedThread3() {
        class NamedThread extends Thread {

            public NamedThread(){
                super("namedThread");
            }

            public NamedThread(String threadName){
                super(threadName);
            }

            public void run() {
                threadLogic();
            }
        }
        ;

        NamedThread namedThread3 = new NamedThread("namedThread3 named by use super in constructor");
        namedThread3.start();
    }

    public static void threadLogic() {
        try {
            Thread.sleep(100000);
            System.out.println("finished");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 线程interrupt举例
     * 通常可用于循环中较长时间操作,对中断进行响应
     */
    public static void threadInterruptExam() {
        count1InInterruptExam = 0;
        count2InInterruptExam = 0;
        Thread threadHasHandedInterrupt = new Thread("thread has handed interrupt") {

            public void run() {
                for (int i = 1; i <= 100000000; i++) {
                    if (i % 3 == 0) {
                        count1InInterruptExam++;
                    } else if (i % 3 == 1) {
                        count1InInterruptExam--;
                    }
                    if (Thread.interrupted()) {
                        System.out.println("thread be interrupted, set count to 123456");
                        count1InInterruptExam = 123456;
                    }
                }
            }
        };
        threadHasHandedInterrupt.start();
        Thread threadNotHandInterrupt = new Thread("thread does not handle interrupt") {

            public void run() {
                for (int i = 1; i <= 100000000; i++) {
                    if (i % 3 == 0) {
                        count2InInterruptExam++;
                    } else if (i % 3 == 1) {
                        count2InInterruptExam--;
                    }
                }
            }
        };
        threadNotHandInterrupt.start();

        try {
            Thread.sleep(1 * 1000);
            threadHasHandedInterrupt.interrupt();
            threadNotHandInterrupt.interrupt();
            Thread.sleep(1 * 1000);
            System.out.println("count in thread that has handed interrupt :" + count1InInterruptExam);
            System.out.println("count in thread that does not hand interrupt :" + count2InInterruptExam);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

其中查看Thread的java源代码可以查看:http://trinea.iteye.com/blog/1351233

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个简单的Java实现,用于在项目启动时根据线程池实现多线程执行service层代码的完整代码: ```java import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class StartupExecutor { private static final int THREAD_POOL_SIZE = 5; // 线程池大小 public static void executeServices() { ExecutorService executorService = Executors.newFixedThreadPool(THREAD_POOL_SIZE); // 这里可以通过Spring的ApplicationContext获取所有的service bean // 然后将每个service bean的方法包装成一个Runnable,提交给线程池执行 // 这里仅作演示,我们手动创建一个DummyService对象 DummyService dummyService = new DummyService(); // 将DummyService的doSomething方法包装成一个Runnable Runnable runnable = () -> dummyService.doSomething(); // 提交给线程池执行 executorService.submit(runnable); // 线程池执行完毕后需要关闭 executorService.shutdown(); } private static class DummyService { public void doSomething() { // 在这里编写需要执行的service层代码 } } } ``` 在上面的代码,我们首先定义了一个常量 `THREAD_POOL_SIZE`,用于指定线程池的大小。然后在 `executeServices()` 方法,我们创建了一个固定大小的线程池,并手动创建了一个 `DummyService` 对象作为示例。 接着,我们将 `DummyService` 的 `doSomething()` 方法封装成一个 `Runnable` 对象,并提交给线程池执行。在实际项目,我们可以通过Spring的ApplicationContext获取所有的service bean,并将每个service bean的方法都封装成一个 `Runnable` 对象,然后提交给线程池执行。 最后,我们在 `executeServices()` 方法关闭了线程池。这是一个好的习惯,避免线程池一直占用系统资源。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值