假设在主线程中的某个对象需要传入到另外一个线程中进行处理,那么两个线程之间如何传递参数?例如:主程序中有个字符串
String s = "hello world";
,使用异步子线程进行空格拆分,结果应该输出hello
和world
两个单词,实现方式如下:
这种方式其实不是参数传递,而是子线程和主线程共享同一个字符串对象,使用log.debug
日志可以看到线程信息,你可以替换为System.out.println();
@Slf4j
public class ThreadTest1 {
public static void main(String[] args) throws InterruptedException {
String s = "hello world";
log.debug(s);
new Thread(()->{
String[] res = s.split(" ");
log.debug(res[0]);
log.debug(res[1]);
}).start();
Thread.sleep(1000);
}
}
如果采用实现Runnable
的方式应该如何实现呢?如下:
public class ThreadTest3 implements Runnable {
public static void main(String[] args) throws InterruptedException {
new ThreadTest3().handler();
}
public void handler() throws InterruptedException {
String s = "hello world";
log.debug(s);
// 这里应该写入你的代码
Thread.sleep(1000);
}
@Override
public void run() {
// 这里应该进行字符串分割
}
}
这里还是使用共享参数的方式,将字符串抽取为成员方法,然后在handler()中将局部变量赋值给成员变量即可。这里使用牛一点的实现,使用任务队列的方式实现。好处是如果有非常多的变量,创建太多的成员变量非常不友好,不如直接将需要执行的指令加入到任务队列中,需要执行时取出即可。注意:任务队列的任务也必须在当前类的作用域中,否则空指针。如下:
@Slf4j
public class ThreadTest3 implements Runnable {
// 任务队列,存放可执行的命令,两个线程需要传参的话通过队列来实现执行逻辑解耦
private static final ConcurrentLinkedQueue<Runnable> tasks = new ConcurrentLinkedQueue<>();
public static void main(String[] args) throws InterruptedException {
new ThreadTest3().handler();
}
public void handler() throws InterruptedException {
String s = "hello world";
log.debug(s);
tasks.add(()->{
String[] res = s.split(" ");
log.debug(res[0]);
log.debug(res[1]);
});
new Thread(this).start();
Thread.sleep(1000);
}
@Override
public void run() {
Runnable task = tasks.poll();
if(task!=null){
task.run();
}
}
}
其实前面两种都是共享参数,并没有真的传递参数,这里创建新的Runnable实现类来达到真正的参数传递:
public class ThreadTest2 {
public static void main(String[] args) throws InterruptedException {
String s = "hello world";
log.debug(s);
new Thread(new Handler(s)).start();
Thread.sleep(1000);
}
static class Handler implements Runnable{
String s;
Handler(String s){
this.s = s;
}
@Override
public void run() {
String[] res = s.split(" ");
log.debug(res[0]);
log.debug(res[1]);
}
}
}
输出结果除了类名不同,应该都是输出如下内容:
20:02:02 [DEBUG] [main] c.c.ThreadTest2 - hello world
20:02:02 [DEBUG] [Thread-0] c.c.ThreadTest2 - hello
20:02:02 [DEBUG] [Thread-0] c.c.ThreadTest2 - world