`

多线程中使用Spring的注入问题

阅读更多

 

在开发中经常会使用Spring的@Autowired来实现对象的自动注入,但是在最近的开发中在多线程中用Spring的@Autowired来自动注入时总是注入不进去,代码如下:

package com.common.base.utils.SpringUtils;

import org.springframework.beans.factory.annotation.Autowired;

import java.util.concurrent.atomic.AtomicInteger;

public class ThreadRunner implements Runnable{

    @Autowired
    private ServiceBean serviceBean;

    private static AtomicInteger count = new AtomicInteger(0);

    @Override
    public void run(){
        if (serviceBean ==null){
            return;
        }
        serviceBean.log();
        count.addAndGet(1);
        System.out.println("当前线程为:" + Thread.currentThread().getName() + "count:" + count);
    }

    public ServiceBean getServiceBean() {
        return serviceBean;
    }

    public void setServiceBean(ServiceBean serviceBean) {
        this.serviceBean = serviceBean;
    }
}

 其中,ServiceBean定义如下:

package com.common.base.utils.SpringUtils;

import org.springframework.stereotype.Service;

@Service("serviceBean")
public class ServiceBean{

    public void log(){
        System.out.println("this is service bean.");
    }
}

 只是简单的输出语句。然后在主线程中,启动线程,如下:

package com.common.base.utils.SpringUtils;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath*:Service-*.xml"})
public class SpringMultiThreadTest{
    @Test
    public void testSpringBean(){
        for (int i=0; i<10000000; i++){
            new Thread(new ThreadRunner()).start();
        }

        try {
            Thread.sleep(1000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

 此时,不会有打印信息,serviceBean为空。

原因:在主线程中使用了:

new ThreadRunner()

 新建了一个实例,并不在Spring容器中,也就没法获得Spring中的bean。

解决办法:

1、将ThreadRunner类也作为一个bean注入到spring容器中,如下:

 

package com.common.base.utils.SpringUtils;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath*:Service-*.xml"})
public class SpringMultiThreadTest{
    @Autowired
    private ThreadRunner threadRunner;
    @Test
    public void testSpringBean(){
        for (int i=0; i<10000000; i++){
            new Thread(threadRunner).start();
        }
        try {
            Thread.sleep(1000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

 问题解决。

2、使用Spring手动获得ServiceBean,首先写一个手动获得Spring bean的工具类:

package com.common.base.utils.SpringUtils;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

/**
 * 直接通过Spring 上下文获取SpringBean,用于多线程环境
 * by jingquan @20160405
 */

public class SpringBeanUtil implements ApplicationContextAware{
	
	private static ApplicationContext applicationContext = null;

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		SpringBeanUtil.applicationContext = applicationContext;
	}

	public static Object getBeanByName(String beanName) {
		if (applicationContext == null){
			return null;
		}
		return applicationContext.getBean(beanName);
	}

	public static <T> T getBean(Class<T> type) {
		return applicationContext.getBean(type);
	}

}

 然后在ThreadRunner类中不自动获取,而是手动获取,代码如下:

package com.common.base.utils.SpringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.concurrent.atomic.AtomicInteger;
public class ThreadRunner implements Runnable{
    private ServiceBean serviceBean;
    private static AtomicInteger count = new AtomicInteger(0);
    public ThreadRunner(){
        this.serviceBean = (ServiceBean)SpringBeanUtil.getBeanByName("serviceBean");
    }
    @Override
    public void run(){
        if (serviceBean ==null){
            return;
        }
        serviceBean.log();
        count.addAndGet(1);
        System.out.println("当前线程为:" + Thread.currentThread().getName() + "count:" + count);
    }

    public ServiceBean getServiceBean() {
        return serviceBean;
    }

    public void setServiceBean(ServiceBean serviceBean) {
        this.serviceBean = serviceBean;
    }
}

 问题解决。

 

分享到:
评论
1 楼 dawntop 2017-12-11  
Spirng4 有@EnableAsync和Async注解,完全可以实现比new thread简单很多的多线程。

相关推荐

Global site tag (gtag.js) - Google Analytics