第一种方法:继承Thread类,重写run方法
import java.util.concurrent.CountDownLatch;
public class MyThread extends Thread{
@Override public void run() { long start = System.currentTimeMillis(); System.out.println(Thread.currentThread().getName()+"开始运行"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"运行结束"); long end = System.currentTimeMillis(); System.out.println(Thread.currentThread().getName()+"运行耗时:"+(end-start)+"毫秒"); }}
public class ThreadMain { public static void main(String[] args) throws InterruptedException { System.out.println("主线程开始运行"); long start = System.currentTimeMillis(); MyThread thread1 = new MyThread(); thread1.setName("thread1"); MyThread thread2 = new MyThread(); thread2.setName("thread2"); MyThread thread3 = new MyThread(); thread3.setName("thread3"); MyThread thread4 = new MyThread(); thread4.setName("thread4"); thread1.start(); /*thread2.start(); thread3.start(); thread4.start(); */ thread1.join(); long end = System.currentTimeMillis(); System.out.println("主现场运行结束,耗时"+(end-start)+"毫秒"); }}
运行结果:
主线程开始运行主现场运行结束,耗时1毫秒Thread-1开始运行thread4开始运行Thread-3开始运行Thread-2开始运行Thread-1运行结束Thread-1运行耗时:1001毫秒thread4运行结束Thread-2运行结束Thread-3运行结束Thread-2运行耗时:1001毫秒thread4运行耗时:1002毫秒Thread-3运行耗时:1001毫秒
思考:子线程还没有结束,主线程先结束了,怎么让主线程在子线程之后结束?
1、在让子线程join进主线程
2、使用Futrue得到线程的返回值,得到返回值主线程才会停止,否则futrue.get()方法会一直阻塞主线程
以上两个方法适合主线程中有一两个子线程,如果子线程多的话,就石乐志了
3、使用CountDownLatch(倒数计数器),创建一个CountDownLatch实例,根据子线程数量初始化倒计数,在子线程中使用CountDownLatch.countDown()方法,使计数-1,在主线程中使用CountDownLatch.await()方法,等计数为零时,主线程继续执行
第二种方法:实现Runnable接口
public class MyRunnable implements Runnable{
@Override public void run() { long start = System.currentTimeMillis(); System.out.println(Thread.currentThread().getName()+"开始运行"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"运行结束"); long end = System.currentTimeMillis(); System.out.println(Thread.currentThread().getName()+"运行耗时:"+(end-start)+"毫秒"); }
}
public class MyRunnableMain { public static void main(String[] args) { System.out.println("主线程开始"); long start = System.currentTimeMillis(); Runnable r1 = new MyRunnable(); Thread thread1 = new Thread(r1); Thread thread2 = new Thread(r1); Thread thread3 = new Thread(r1); Thread thread4 = new Thread(r1); Thread thread5 = new Thread(r1); thread1.start(); thread2.start(); thread3.start(); thread4.start(); thread5.start(); long end = System.currentTimeMillis(); System.out.println("主线程结束,耗时:"+(end-start)+"毫秒"); }}
运行结果:
主线程开始主线程结束,耗时:1毫秒Thread-0开始运行Thread-1开始运行Thread-2开始运行Thread-3开始运行Thread-4开始运行Thread-1运行结束Thread-0运行结束Thread-1运行耗时:1000毫秒Thread-0运行耗时:1000毫秒Thread-2运行结束Thread-3运行结束Thread-3运行耗时:1001毫秒Thread-2运行耗时:1002毫秒Thread-4运行结束Thread-4运行耗时:1001毫秒
思考:thread和runnable两种方式哪种更好?为什么?
runnable方式创建线程更好
使用runnable接口的方式能避免java单继承带来的缺陷
使用runnable接口能够被多个线程共享,适用于多个线程共享资源
第三种方式:Callable接口,带有Future返回值的线程
import java.util.concurrent.Callable;
public class MyCallable implements Callable<String>{ private String name; public MyCallable(String name) { this.name = name; }
@Override public String call() throws Exception { long start = System.currentTimeMillis(); System.out.println(Thread.currentThread().getName()+"开始运行"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"运行结束"); long end = System.currentTimeMillis(); System.out.println(Thread.currentThread().getName()+"运行耗时:"+(end-start)+"毫秒"); return "这是"+name+"线程返回的结果"; }
}
public class MyCallableMain { public static void main(String[] args) { System.out.println("主程序开始运行");// 记录起始时间 long start = System.currentTimeMillis();// 使用list记录Future结果集 List<Future> list = new ArrayList<Future>(); final int POOL_SIZE = 5;// 创建线程池 ExecutorService pools = Executors.newFixedThreadPool(POOL_SIZE); for(int i=0; i<POOL_SIZE; i++){ Callable c = new MyCallable("callable"+(i+1));// 获取线程的返回值 Future future = pools.submit(c); list.add(future); }// 线程池必须关闭,否则主程序无法结束 pools.shutdown(); for(Future future : list){ try { System.out.println(future.get().toString()); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } long end = System.currentTimeMillis(); System.out.println("主程序运行结束,耗时:"+(end-start)+"毫秒"); }}
运行结果:
主程序开始运行pool-1-thread-2开始运行pool-1-thread-1开始运行pool-1-thread-4开始运行pool-1-thread-5开始运行pool-1-thread-3开始运行pool-1-thread-2运行结束pool-1-thread-1运行结束pool-1-thread-2运行耗时:1001毫秒pool-1-thread-1运行耗时:1001毫秒这是callable1线程返回的结果这是callable2线程返回的结果pool-1-thread-5运行结束pool-1-thread-4运行结束pool-1-thread-4运行耗时:1002毫秒pool-1-thread-5运行耗时:1001毫秒pool-1-thread-3运行结束pool-1-thread-3运行耗时:1002毫秒这是callable3线程返回的结果这是callable4线程返回的结果这是callable5线程返回的结果主程序运行结束,耗时:1007毫秒
补充:使用callable创建线程的好处是:它可以带有返回值,配合Future接口来接受callable的返回值
接受返回值的方式有两种:
第一种:使用线程池来执行线程,submit()方法返回future对象
第二种:使用Future接口的FutureTask实现类来接受callable的实现类,FutureTask类还实现了Runnable接口,因此可以作为Thread类的target入参
转载于:https://www.cnblogs.com/lenghui/p/7571640.html
