最近在写多线程测试程序的时候遇到了一些问题,根据参考及自己实践,做记录如下
Java中同时启动多个线程并传入不同参数
threadLocal原理及说明参考
Java中同时启动多个线程(CountDownLatch)
Java向线程传入参数
Java向线程传入参数的三种方法
可以通过构造器或者set的方式,或者回调函数传入
同时启动多个线程并传入不同的参数(自己练习)
方式一:使用threadLocal+CountDownLatch
- threadLocal用于存储线程的局部变量,不同的线程启动后存入线程各自的参数,然后去获取。
- CountDownLatch用于控制线程同时启动
public class Test {
ThreadLocal<String> threadLocal=new ThreadLocal<String>();
@Test
public void findOrderSplitDetailsTest() throws InterruptedException {
QueryOrderByPayReqVo reqVo=new QueryOrderByPayReqVo();
reqVo.setOrderId("56290014401");
orderQueryResource.findOrderSplitDetails(reqVo);
Thread.sleep(1000L);
CreateOrderReqVo reqVo1=new CreateOrderReqVo();
reqVo1.setPayMode(2);
reqVo1.setParentOrderId("56290014401");
reqVo1.setOrderId("56308748910");
CountDownLatch countDownLatch = new CountDownLatch(3);
for (int i=0; i<3; i++) {
//本意是这样实现给不同的线程传入不同的参数,然后因为reqVo是myThread1中的成员变量,不是run方法中的局部变量,所以是不对的
/*if(i==1){
reqVo1.setOrderId("56308748911");
}else if(i==2){
reqVo1.setOrderId("56308748912");
}*/
Thread thread = new Thread(new myThread1(reqVo1,countDownLatch));
thread.setName("线程-" + (i+1));
thread.start();
countDownLatch.countDown();
}
Thread.sleep(1000L);
}
public class myThread1 implements Runnable{
CreateOrderReqVo reqVo;
private final CountDownLatch countDownLatch;
public myThread1(CreateOrderReqVo reqVo,CountDownLatch countDownLatch){
this.reqVo=reqVo;
this.countDownLatch=countDownLatch;
}
@SneakyThrows
@Override
public void run() {
try{
countDownLatch.await();
if(Thread.currentThread().getName().endsWith("1")){
threadLocal.set("1111111");
}else if(Thread.currentThread().getName().endsWith("2")){
threadLocal.set("222222");
}else{
threadLocal.set("3333333");
}
System.out.println("线程"+Thread.currentThread().getName()+" 开始执行");
System.out.println("查询父子单:"+threadLocal.get());
isReceiveVirtualPay(reqVo);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
//isReceiveVirtualPay(reqVo);也是本类中的方法,其可以调用threadLocal.get()输出当前执行改方法的线程的threadLocal存储变量
private void isReceiveVirtualPay(CreateOrderReqVo reqVo) {
System.out.println("我是子单:"+threadLocal.get());
}
}
输出:
线程线程-2 开始执行
线程线程-3 开始执行
查询父子单:3333333
线程线程-1 开始执行
查询父子单:1111111
查询父子单:222222
我是子单:1111111
我是子单:3333333
我是子单:222222
方式二:给线程传入不同的对象实例
- 方式一用threadlocal存储线程局部变量,方式二直接传入新的变量
- 注意点在于每次传入的变量或实例都必须是新的
public class Test {
@Test
public void findOrderSplitDetailsTest() throws InterruptedException {
QueryOrderByPayReqVo reqVo=new QueryOrderByPayReqVo();
reqVo.setOrderId("56290014401");
orderQueryResource.findOrderSplitDetails(reqVo);
Thread.sleep(1000L);
final CreateOrderReqVo reqVo1=new CreateOrderReqVo();
reqVo1.setPayMode(2);
reqVo1.setParentOrderId("56307822401");
reqVo1.setOrderId("56308748910");
final CreateOrderReqVo reqVo2=new CreateOrderReqVo();
reqVo2.setPayMode(2);
reqVo2.setParentOrderId("56307822401");
reqVo2.setOrderId("56308748911");
final CreateOrderReqVo reqVo3=new CreateOrderReqVo();
reqVo3.setPayMode(2);
reqVo3.setParentOrderId("56307822401");
reqVo3.setOrderId("56308748912");
CountDownLatch countDownLatch = new CountDownLatch(3);
for (int i=0; i<3; i++) {
Thread thread=null;
if(i==1){
thread=new Thread(new myThread1(reqVo2,countDownLatch));
}else if(i==2){
thread=new Thread(new myThread1(reqVo3,countDownLatch));
}else{
thread=new Thread(new myThread1(reqVo1,countDownLatch));
}
thread.setName("线程-" + (i+1));
thread.start();
countDownLatch.countDown();
}
Thread.sleep(1000L);
}
public class myThread1 implements Runnable{
CreateOrderReqVo reqVo;
private final CountDownLatch countDownLatch;
public myThread1(CreateOrderReqVo reqVo,CountDownLatch countDownLatch){
this.reqVo=reqVo;
this.countDownLatch=countDownLatch;
}
@SneakyThrows
@Override
public void run() {
try{
countDownLatch.await();
System.out.println("线程"+Thread.currentThread().getName()+" 开始执行");
System.out.println("查询父子单:"+reqVo.getOrderId());
isReceiveVirtualPay(reqVo);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
//isReceiveVirtualPay(reqVo);也是本类中的方法,这里每个线程传入的都是新的CreateOrderReqVo对象,所以是不同的
private void isReceiveVirtualPay(CreateOrderReqVo reqVo) {
System.out.println("我是子单:"+reqVo.getOrderId());
}
}
输出:
线程线程-2 开始执行
查询父子单:56308748911
线程线程-3 开始执行
查询父子单:56308748912
线程线程-1 开始执行
查询父子单:56308748910
我是子单:56308748910
我是子单:56308748911
我是子单:56308748912
- 另外方式二也可以这样写,结果是一样的
public class Test {
@Test
public void findOrderSplitDetailsTest() throws InterruptedException {
QueryOrderByPayReqVo reqVo=new QueryOrderByPayReqVo();
reqVo.setOrderId("56290014401");
orderQueryResource.findOrderSplitDetails(reqVo);
Thread.sleep(1000L);
final CreateOrderReqVo reqVo2=new CreateOrderReqVo();
reqVo2.setPayMode(2);
reqVo2.setParentOrderId("56307822401");
reqVo2.setOrderId("56308748911");
final CreateOrderReqVo reqVo3=new CreateOrderReqVo();
reqVo3.setPayMode(2);
reqVo3.setParentOrderId("56307822401");
reqVo3.setOrderId("56308748912");
CountDownLatch countDownLatch = new CountDownLatch(3);
//相关与每次启动线程中时候给线程传入不同的对象(对象必须是新new的)
for (int i=0; i<3; i++) {
if(i==1){
threadEx(reqVo2,i,countDownLatch);
}else if(i==2){
threadEx(reqVo3,i,countDownLatch);
}else{
threadEx(reqVo1,i,countDownLatch);
}
countDownLatch.countDown();
}
Thread.sleep(1000L);
}
public void threadEx(final CreateOrderReqVo reqVo, int i, final CountDownLatch countDownLatch){
new Thread(new Runnable(){
@SneakyThrows
@Override
public void run() {
countDownLatch.await();
System.out.println("线程"+Thread.currentThread().getName()+" 开始执行");
System.out.println("查询父子单:"+reqVo.getOrderId());
isReceiveVirtualPay(reqVo);
}
},"线程-" + (i+1)).start();
}
//isReceiveVirtualPay(reqVo);也是本类中的方法,这里每个线程传入的都是新的CreateOrderReqVo对象,所以是不同的
private void isReceiveVirtualPay(CreateOrderReqVo reqVo) {
System.out.println("我是子单:"+reqVo.getOrderId());
}
}
这篇博客介绍了在Java中如何同时启动多个线程并传入不同参数,通过两种方法实现:一是结合threadLocal和CountDownLatch,二是直接传入不同的对象实例。文章详细讲解了threadLocal的原理和CountDownLatch的使用,并提供了实践代码示例。

10万+

被折叠的 条评论
为什么被折叠?



