1、继承Thread
Thread类本身实现了 Runnable 接口。 从某个角度Thread类可以看成是Runnable的包装类
如果需要在线程开启时携带参数,使用在线程类使用构造函数来实现
public class ThreadDemo1 {
public static void main(String[] args) {
Thread thread1 = new ThreadDemo();
Thread thread2 = new ThreadDemo();
//开启一个新线程调用start() 如果是调用run()方法则不会开启新线程,而是用主线程执行
thread1.start();
thread2.start();
}
}
class ThreadDemo extends Thread{
public void run(){
System.out.println("这个线程在疯狂的跑");
}
}
使用匿名内部类实现
new Thread(){
public void run(){
System.out.println("在方法内开启了新线程");
}
}.start();
2、实现Runnable接口
和继承Thread类实现基本一致,不过是我们自行实现了Runnable接口,然后再用Thread包装。
因java不支持多继承,在类已经存在继承的情况下,可以使用这种方式
public class ThreadDemo2 {
public static void main(String[] args) {
Thread thread1 = new Thread(new RunnableImpl());
Thread thread2 = new Thread(new RunnableImpl());
thread1.start();
thread2.start();
}
}
class RunnableImpl implements Runnable{
@Override
public void run() {
System.out.println("这个线程也在疯狂的跑");
}
}
匿名内部类实现
new Thread(new Runnable(){
@Override
public void run() {
System.out.println("用匿名内部类和Runnable启动了一个新线程");
}
}).start();
3、实现Callable接口
实现Callable接口的线程,可获取返回值
使用FutureTask get()方法获取返回值,get()方法是阻塞的,会一直阻塞主线程等待返回结果。
public class ThreadDemo3 {
public static void main(String[] args) throws InterruptedException, ExecutionException {
CallableImpl callable1 = new CallableImpl("标记xxx");
FutureTask<String> futhre = new FutureTask<String>(callable1);
Thread thread1 = new Thread(futhre);
thread1.start();
String res = futhre.get();
System.out.println("测试futhre.get是不是阻塞的");
System.out.println(res);
}
}
/**Callable 是个泛型类,可以指定返回参数的类型, 这里把其指定为String**/
class CallableImpl implements Callable<String>{
private String reqStr;
//重载了一个构造方法,这样我们在线程创建时,还能带入参数
public CallableImpl(String str){
reqStr = str;
}
public CallableImpl(){
};
@Override
public String call() throws Exception {
System.out.println("线程在运行,其标记为"+reqStr);
//do something 线程执行,然后可返回一个对象
Thread.sleep(2000);
String resStr = reqStr+"跑完了,并返回了这个信息";
return resStr;
}
}
4、线程池 与 Callable
使用ExecutorService管理线程池。
如不需要返回值,可将代码种的Callable 实现换乘 Runnable实现即可
线程池关闭后,不能再往其内添加新线程,但已加入到池中的线程会继续执行完
package a.caixl.thread;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class ThreadDemo4 {
public static void main(String[] args) throws InterruptedException, ExecutionException {
/**开一个线程池,并设定其线程数**/
int poolSize = 5;
ExecutorService pool = Executors.newFixedThreadPool(poolSize);
List<Future<String>> list = new ArrayList<Future<String>>();
for(int i=0;i<20;i++){
CallableImpl2 callable = new CallableImpl2(i+"");
Future<String> future = pool.submit(callable); //将callable放入池内等待执行,submit不是阻塞方法
//future.get(); //如果再这get会阻塞主线程,那线程池就没有意义。 因此保存起来之后统一执行
list.add(future);
}
pool.shutdown(); //关闭后,不可再往池内submit , 但已在池内的线程会继续执行完
/**获取返回值**/
for(Future<String> future : list){
System.out.println(future.get());
}
}
}
/**Callable 是个泛型类,可以指定返回参数的类型, 这里把其指定为String**/
class CallableImpl2 implements Callable<String>{
private String reqStr;
//重载了一个构造方法,这样我们在线程创建时,还能带入参数
public CallableImpl2(String str){
reqStr = str;
}
public CallableImpl2(){
};
@Override
public String call() throws Exception {
System.out.println("线程在运行,其标记为"+reqStr);
//do something 线程执行,然后可返回一个对象
Thread.sleep(2000);
String resStr = reqStr+"跑完了,并返回了这个信息";
return resStr;
}
}