进程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