この記事では、springboot でマルチスレッドを開発するときに注意すべき点について説明します。 (要約) 必要な友人が参考になれば幸いです。
springboot をベースとしたマルチスレッドプログラムの開発プロセスでは、Spring コンテナ自体を管理する必要があるため、springboot の利点が最大限に発揮されます。したがって、この記事は主に、開発時に両者を組み合わせる際に注意すべき事項を記録するために使用されます。
最初のステップは、スレッド クラスのインスタンスを管理用の sping コンテナに挿入することです。
@Configuration @SpringBootApplication @Import({ThreadConfig.class}) public class ThreadApp implements CommandLineRunner { public static void main(String[] args) throws Exception { ApplicationContext app = SpringApplication.run(ThreadApp .class, args); //这里主要保存上下文对象实例,需要加上。SpringBootUtils类网上很多,可以自己搜下 SpringBootUtils.setApplicationContext(app); } //access command line arguments @Override public void run(String... args) throws Exception { //do something } } //ComponentScan注解会扫描com.demo.thead下,也就是多线程类所在的包下的文件 @Configuration @ComponentScan(basePackages = { "com.demo.thread"}) public class ThreadConfig{ }
ここでは、springboot @Import を使用します。 ThreadConfig をスキャンするためのアノテーション @Component などのパッケージ内のアノテーションを持つサンプルが Spring コンテナーに挿入されます。
その後、私のビジネス シナリオには 2 つの状況が開始されます。
1 、プログラムは実行中に自動的に開始されます。
#これは一般的な実行可能プログラム内で実行され、コードを通じてスレッドを開始することができます。ただし、springboot では、 @PostConstruct アノテーションを使用して、Bean コンテナーに挿入されたスレッド オブジェクトを自動的に開始できるようにすることができます。@Component public class demoThread extends Thread { //注意这里,如果你没有实现把多线程类的实例注入到spring容器中,这里你是无法拿到其他自动装配的对象实例的的,这也是我们第一步的意义所在。 @Autowired private XxxService xxxService; @PostConstruct public void start() { super.start(); } public void run() { // Ok,在这里你就可以实现线程要实现的功能逻辑了,自然也可以直接使用装配好的sevice对象实例。 } }2.プログラムでは、kafka からデータを受信してスレッド処理を開始するなど、スレッドが開かれたときに Started する必要があります。もちろん、この場合、最初のステップを実行してスレッド クラスのインスタンスを sping コンテナに注入する必要もあります##。 #
private TaskThread thread; private ExecutorService taskPool= new ThreadPoolExecutor( 5, 10, 1000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(10), new ThreadPoolExecutor.CallerRunsPolicy()); @KafkaListener(topics = "xxTopic") public void receive(ConsumerRecord<Object, Object> consumerRecord) { JSONObject json = JSON.parseObject(consumerRecord.value().toString()); //通过SpringBootUtils获取线程类的实例 thread = SpringBootUtils.getBean(TaskThread.class); //启动线程 //new Thread(thread).start() ; //向线程对象里传值 thread.init(i); //放入线程池执行 taskPool.execute(thread); }
//注意这里是否添加@Scope("prototype")注解 @Component @Scope("prototype") public class TaskThread implements Runnable{ protected int value=0; @Autowired private XxxService xxxService; //ThreadLocal 对象,单例模式下可以保证成员变量的线程安全和独立性。 public ThreadLocalc0f559cc8d56b43654fcbe4aa9df7b4a valueLocal = new ThreadLocal 46fc8f240055341038a5bc0c386009d9 () { @Override protected Integer initialValue() { return 0; } }; protected static final Logger LOG = LoggerFactory.getLogger(GpsTaskThread.class); @Override public final void run() { try { LOG.info(value+""); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } public void init(int Value) { this.value=Value; } }
ここでは、TaskThread スレッド クラスに @Scope("prototype") アノテーションを追加する必要があるかどうかに注意する必要があります。 spirngboot でマルチインスタンスモードまたはデフォルトのシングルトンモードに設定します。
シングルトンモードでは、SpringBootUtils.getBean(TaskThread.class) は毎回同じオブジェクトを返しますが、毎回新しいオブジェクトを作成する必要はありませんが、メンバー変数のスレッドは保証されません。安全性、つまりスレッドプール内の実行スレッドの値が共有されます。マルチインスタンスモードでは、毎回新しいスレッドオブジェクトが作成されるため、上記の問題は発生しません。
したがって、ここで注意してください。上記のサンプル コードであっても、通常の Web 開発であっても、spingboot はデフォルトでシングルトン モードに設定されており、カスタム メンバー変数はスレッドアンセーフである必要があります。 ThreadLocal またはその他のメソッドを介して。現在のビジネス シナリオに戻ります。ここでは、各スレッドが互いに影響を与えることなく異なる値を処理し、@Scope("prototype") アノテーション モデルを通じて TaskThread を複数のインスタンスに設定する必要があります。 。
概要
上記の例を通して、スプリングブートとマルチスレッドの組み合わせが比較的簡単であることがわかります。設定を通じて、スプリング コンテナ内とスレッド内のスレッド クラスを管理できます。 . スピンコンテナ内のオブジェクトインスタンスを使用します。同時に、使用中のスレッドの安全性の問題と内部動作メカニズムの問題に意識的に注意を払う必要があります。もちろん、ここでの理解はまだ比較的簡単です。間違っている点があれば、指摘して説明してください。
以上がspringboot でマルチスレッドを開発する際に注意すべき点は何ですか? (要約)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。