[Java multithreading] How to pass data to a thread and let the thread return data

1. How to pass data to the thread

1. Pass data through the construction method

When creating a thread, you must create an instance of the Thread class or its subclasses. So before you can start method is called by 线程类的构造方法the data into threads. And use the incoming data 成员变量接收so that the thread body can use it

/**
 * TODO 测试线程传递参数1-通过构造方法传递数据
 */
public class TestThreadPassParam1 extends Thread {
    
    
    //用于接受构造方法传进来的数据
    private String name;

	//构造方法
    public TestThreadPassParam1(String name) {
    
    
        this.name = name;
    }
    
    //线程体
    @Override
    public void run() {
    
    
        System.out.println("hello " + name);
    }
    
    public static void main(String[] args) {
    
    
        Thread thread = new TestThreadPassParam1("world");
        thread.start();
    }
}

If the data is passed through the construction method, the data is already in place before the thread runs, so that it will not cause the data to be passed in after the thread runs. If you want to pass more complex data, you can pass the data through class methods or class variables.

2. Pass data through variables and methods

There are generally two opportunities to pass in data to an object. The first opportunity is to pass in the data through the construction method when the object is created. The other opportunity is to define a series of public methods or variables in the class (also called Is a field). Then after creating the object, assign values ​​one by one through the object instance. The following code is a revised version of the MyThread1 class, using a setName method to set the name variable:

/**
 * @Description TODO 测试线程传递参数2-通过变量和方法传递数据
 */
public class TestThreadPassParam2 extends Thread {
    
    
   //传递参数
    private String food;

    public void setFood(String food) {
    
    
        this.food = food;
    }

	//线程体
    @Override
    public void run() {
    
    
        System.out.println("吃" + food);
    }

    public static void main(String[] args) {
    
    
        TestThreadPassParam2 myThread = new TestThreadPassParam2();
        myThread.setFood("包子");

        Thread thread = new Thread(myThread);
        thread.start();
    }
}

3. Pass data through the callback function

The above two methods of passing data to threads are the most commonly used. Are in 主线程main (), 主动the incoming data 线程类is. For the thread, it is passive to receive these data. However, in some applications, data needs to be dynamically obtained during the thread's running process.

For example: Three random numbers are generated in the run method of the following code, and then the sum of these three random numbers is calculated through the process method of the Work class, and the result is returned through the value of the Data class. As can be seen from this example, before returning the value, three random numbers must be obtained. In other words, this value cannot be passed into the thread class in advance.

import java.util.Random;
/**
 * @Description TODO 测试线程传递参数3-通过回调函数传递数据
 */
public class TestThreadPassParam3 extends Thread {
    
    
    //传递参数
    private Work work;

    //构造方法
    public TestThreadPassParam3(Work work) {
    
    
        this.work = work;
    }

    //线程体
    public void run() {
    
    
        //声明Data对象
        Data data = new Data();

        //声明随机对象
        Random random = new Random();
        int n1 = random.nextInt(1000);//随机数1
        int n2 = random.nextInt(2000);//随机数2
        int n3 = random.nextInt(3000);//随机数3

        //线程内调用work对象的.process方法
        work.process(data, n1, n2, n3);   // 使用回调函数

        System.out.println(n1 + "+" + n2 + "+" + n3 + "=" + data.value);
    }

    public static void main(String[] args) {
    
    
        Thread thread = new TestThreadPassParam3(new Work());
        thread.start();
    }
}

//计数器
class Data {
    
    
    public int value = 0;
}

//在线程内回调,用于将numbers的值累加到Data.value
class Work {
    
    
    public void process(Data data, Integer... numbers) {
    
    
        for (Integer n : numbers) {
    
    
            data.value += n;
        }
    }
}

The ones in the above code process方法are called callback functions . Essentially, the callback function is the event function . The process of calling the callback function is just that 最原始的触发事件的过程. In this example, calling process方法to get the data is equivalent to在run方法中引发了一个事件。

2. How to let the thread return data

Returning data from a thread is similar to passing data to a thread. Data can also be returned through class members and callback functions, but there are some differences between class members in returning data and passing data

1. The main thread waits

Using this method to return data requires that the thread is completed before the data can be obtained through class variables or methods

/**
 * TODO 测试线程返回数据1-通过主线程等待返回数据
 */
public class TestThreadReturnData1 extends Thread {
    
    
    private Count count;

    TestThreadReturnData1(Count count) {
    
    
        this.count = count;
    }

    @Override
    public void run() {
    
    
        for (int i =0 ;i<10;i++) {
    
    
            this.count.setValue(this.count.getValue()+1);
        }
    }

    public static void main(String[] args) throws InterruptedException {
    
    
        Count count = new Count();
        Thread thread = new Thread(new TestThreadReturnData1(count));
        thread.start();

        // 获取子线程的返回值:主线程等待法
        while (count.getValue() == 0) {
    
    
            Thread.sleep(1000);
        }
        System.out.println(count.getValue());
        System.out.println("主线程执行完毕");
    }
}

//计数器
@Data
class Count {
    
    
    public int value = 0;
}

Insert picture description here

2. The Join method blocks the current thread to wait for the completion of the child thread execution

使用join方法可以让子线程执行完毕后再执行主线程,本质和通过循环判断一样

import lombok.Data;

/**
 * @Description TODO 测试线程返回数据1-通过Join方法阻塞当前线程以等待子线程执行完毕返回数据
 */
public class TestThreadReturnData2 extends Thread {
    
    
    private Count2 count;

    TestThreadReturnData2(Count2 count) {
    
    
        this.count = count;
    }

    @Override
    public void run() {
    
    
        for (int i =0 ;i<10;i++) {
    
    
            this.count.setValue(this.count.getValue()+1);
        }
    }

    public static void main(String[] args) throws InterruptedException {
    
    
        Count2 count = new Count2();
        Thread thread = new Thread(new TestThreadReturnData2(count));
        thread.start();

        // 获取子线程的返回值:Thread的join方法来阻塞主线程,直到子线程返回
        thread.join();

        System.out.println(count.getValue());
        System.out.println("主线程执行完毕");
    }
}

//计数器
@Data
class Count2 {
    
    
    public int value = 0;
}

Insert picture description here

3. Use Callable interface and FutureTask

The Callable interface was added in JDK1.5. Implementing this interface and rewriting the call() method can also create a new thread, and this method has a return value!

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class CallableAndFutureReturnData implements Callable<String> {
    
    
    public static void main(String[] args) throws ExecutionException, InterruptedException {
    
    
        /***
         * FutureTask 实现了 Runnable接口,所以新建线程的时候可以传入FutureTask
         * FutureTask重写的run方法中实际是调用了Callable接口在call()方法,所以执行线程的时候回执行call方法的内容
         */

        FutureTask<String> task = new FutureTask<String>(new CallableAndFutureReturnData());
        new Thread(task).start();

        if (!task.isDone()) {
    
    
            System.out.println("task has not finished, please wait!");
        }

        System.out.println("task return: " + task.get());
    }

    @Override
    public String call() throws Exception {
    
    
        String value = "over";
        System.out.println("Ready to work");
        Thread.currentThread().sleep(5000);
        System.out.println("task done");
        return value;
    }
}

Insert picture description here
Here need to pay attention to the two methods of FutrueTask:

  • isDone : Use the state variable to determine whether the call method has been executed
  • get : If the call method has been executed, it returns the return value of the call method, and if the call method is not executed, it will keep blocking

4. Use thread pool

public class ThreadPoolDemo {
    
    
    public static void main(String[] args) {
    
    
        //创建线程池
        ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
        //通过线程池管理线程MyCallable
        Future<String> future = newCachedThreadPool.submit(new MyCallable());

        //如果提交的任务未完成
        if (!future.isDone()) {
    
    
            System.out.println("task has not finished, please wait!");
        }

        try {
    
    
            System.out.println(future.get());
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        } catch (ExecutionException e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            //关闭线程池
            newCachedThreadPool.shutdown();
        }
    }
}

class MyCallable implements Callable<String> {
    
    
    //线程体
    @Override
    public String call() throws Exception {
    
    
        String value = "over";
        System.out.println("Ready to work");
        Thread.currentThread().sleep(5000);
        System.out.println("task done");
        return value;
    }
}

Guess you like

Origin blog.csdn.net/qq877728715/article/details/107003268