一般来说,在java中实现高并发是基于多线程编程的,所谓并发,也就是多个线程同时工作,来处理我们的业务,在机器普遍多核心的今天,并发编程的意义极为重大,因为我们有多个cpu供线程使用,如果我们的应用依然只使用单线程模式来工作的话,对极度浪费机器资源的。所以,学习java并发知识的首要问题是:如何创建一个线程,并且让这个线程做一些事情?这是java并发编程内容的起点,下面将分别介绍多个创建线程,并且让线程做一些事情的方法。
继承Thread类
继承Thread类,然后重写run方法,这是第一种创建线程的方法。run方法里面就是我们要做的事情,可以在run方法里面写我们想要在新的线程里面运行的任务,下面是一个小例子,我们继承了Thread类,并且在run方法里面打印出了当然线程的名字,然后sleep1秒中之后就退出了:
package com.iccboy.study.concurrent;
public class ThreadDemo {
public static void main(String... args) {
DemoThread demoThread = new DemoThread();
// start the thread
demoThread.start();
}
}
class DemoThread extends Thread {
@Override
public void run() {
System.out.println("Current Thread Name:" + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
实现Runnable接口
启动一个线程的第二种方法是实现Runnable接口,然后实现其run方法,将你想要在新线程里面执行的业务代码写在run方法里面,下面的例子展示了这种方法启动线程的示例,实现的功能和上面的第一种示例是一样的:
package com.iccboy.study.concurrent;
public class RunnableaDemo {
public static void main(String... args) {
MyRunnanle aRunnanle = new MyRunnanle();
Thread thread = new Thread(aRunnanle);
thread.start();
}
}
class MyRunnanle implements Runnable {
public void run() {
System.out.println("Current Thread Name:" + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
在启动线程的时候,依然还是使用了Thread这个类,只是我们在构造函数中将我们实现的Runnable对象传递进去了,所以在我们执行Thread类的start方法的时候,实际执行的内容是我们的Runnable的run方法。
使用FutureTask
启动一个新的线程的第三种方法是使用FutureTask
package com.iccboy.study.concurrent;
import java.util.Date;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class FutureTaskDemo {
public static void main(String... args) {
MyCallAble callAble = new MyCallAble();
FutureTask<String> futureTask = new FutureTask<>(callAble);
Thread thread = new Thread(futureTask);
thread.start();
do {
System.out.println(new Date());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
} while (!futureTask.isDone());
try {
String result = futureTask.get();
System.out.println("Result:" + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
class MyCallAble implements Callable<String> {
@Override
public String call() throws Exception {
Thread.sleep(1000);
return "Thread-Name:" + Thread.currentThread().getName();
}
}
可以看到,使用FutureTask来启动一个线程之后,我们可以监控这个线程是否完成,上面的示例中主线程会一直等待这个新创建的线程直到它返回,其实只要是Future提供的接口,我们在FutureTask中都可以使用,这极大的方便了我们,Future在并发编程中的意义极为重要,Future代表一个未来会发生的东西,它是一种暗示,一种占位符,它示意我们它可能不会立即得到结果,因为它的任务还在运行,但是我们可以得到一个对这个线程的监控对象,我们可以对线程的执行做一些判断,甚至是控制,比如,如果我们觉得我们等了太久,并且我们觉得没有必要再等待下去的时候,就可以将这个Task取消,还有一点需要提到的是,Future代表它可能正在运行,也可能已经返回,当然Future更多的暗示你可以在等待这个结果的同时可以使用其他的线程做一些其他的事情,当你真的需要这个结果的时候再来获取就可以了,这就是并发,理解这一点非常重要。
https://www.cnblogs.com/a8457013/p/7819034.html
Java并发编程:Callable、Future和FutureTask