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;
	}
}