进程vs线程:
进程:每个程序被运行加载到内存之后,都会被操作系统作为一个进程,进程是处于运行过程中的程序,是具有独立功能,被操作系统进行资源分配和调度的独立单元。
线程:一个进程里面可以拥有多个线程,线程拥有自己的堆栈,程序计数器和自己的局部变量,但是不拥有系统资源,多个线程共享进程的系统资源。
创建线程的三种方式:
1.继承Thread类创建线程类
继承Thread类,重写run()方法,该run()方法就代表程序需要完成的任务。创建Thread子类的实例,即创建线程对象。然后通过start()方法启动线程。
1 public class MyThread extends Thread { 2 private int count; 3 4 @Override 5 public void run() { 6 7 for (; count < 100; count ++) { 8 System.out.println(getName() + "---" + count); 9 } 10 } 11 12 public static void main(String[] args) { 13 for (int i = 0; i < 100; i++) { 14 System.out.println(Thread.currentThread().getName() + i); 15 if (i == 20) { 16 new MyThread().start(); 17 new MyThread().start(); 18 } 19 } 20 } 21 }
2.实现Runnable接口来创建并启动多线程
继承Runnable接口,并重写该接口的run()方法。创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread类对象,该Thread类对象才是真正的多线程对象。然后调用start()方法来执行该Thread实例线程。
示例:
1 public class MyRunableThread implements Runnable { 2 3 private int count = 0; 4 5 @Override 6 public void run() { 7 for (; count < 20; count ++){ 8 System.out.println(Thread.currentThread().getName() + "--" + count); 9 } 10 } 11 12 public static void main(String[] args){ 13 for (int i=0; i<30; i++){ 14 System.out.println(Thread.currentThread().getName() + "--" + i); 15 if (i == 20){ 16 MyRunableThread myRunableThread = new MyRunableThread(); 17 new Thread(myRunableThread, "子线程1").start(); 18 new Thread(myRunableThread, "子线程2").start(); 19 } 20 } 21 } 22 }
3.使用Callable和Future创建线程
Java无法将任意方法包装成线程执行体,在Java5之后提供了一个Callable接口,该接口提供了call()方法作为线程执行体,类似于Runnable接口,call()方法类似于run()方法。但是call()方法比run()方法作为执行体,就更加强大。
1.call()可以有返回值。
2.call()可以声明抛出异常。
public class MyCallableThread { public static void main(String[] args) { //FutureTask包装Callable实例对象,此处使用了Lambda表达式来创建一个Callable对象 FutureTask<Integer> task = new FutureTask<>(() -> { int count = 0; for (; count < 10; count++) { System.out.println(Thread.currentThread().getName() + "--" + count); } return count; }); for (int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getName() + "--" + i); if (i == 20) { new Thread(task, "callAbleThread").start(); } } try { //Callable线程获取返回值 System.out.println("线程的返回值为:" + task.get()); } catch (Exception e) { e.getStackTrace(); } } }
Future接口代表Callable接口里call()方法的返回值,FutureTask是Future接口的实现类,FutureTask实现类实现了Future接口和Runnable接口,可以做为Thread类的Target。Future接口里提供了如下几个方法来控制实现Callable接口的任务:
boolean cancel(Boolean mayInterruptIfRunning) 试图取消该Future里关联的Callable任务。
V get()返回Callable任务里的返回值。该方法会阻塞程序,必须等子线程结束后,才会得到返回值。
V get(long timeOut, TimeUnit unit)返回Callable任务里的返回值。该方法让程序最多阻塞的最长时间,由timeOut和unit来指定,如果超时,Callable接口依然没有返回值,则会抛出TimeOutException异常。
boolean isCancelled()如果在Callable任务正常执行前被取消,则返回true
boolean isDone()如果Callable任务已经完成,则返回true。
Callable接口创建线程的步骤:
1)创建Callable接口的实现类,并实现Call()方法,该方法作为线程的执行体,且该Call()方法有返回值,在创建Callable实现类的实例。也可以使用Lambda表达式来创建Callable接口的实例。
2)使用FutureTask对象来包装Callable接口的实现类实例,FutureTask包装了Callable实现类的返回值。
3)使用FutureTask对象作为Thread对象的target创建并启动多线程。
4)调用FutureTask对象的get()方法来获取子线程执行结束后的返回值。
控制线程
(1)join线程
join()方法时Thread提供一个线程等待另外一个线程完成的方法。
来源:https://www.cnblogs.com/seedss/p/12636121.html