最近,在梳理自己的知识体系,回顾基础知识,故做一下记录。
说起线程,就会联想到进程,那么先来说说,什么是进程。
进程就是运行的程序。就比如说,像qq、微信我们将其打开,操作系统会给这个程序分配一定的资源(主要是内存资源),这样就是有一个qq的进程在运行。
那么,什么是线程呢。线程是CPU调度的基本单位,每个线程执行的都是某一个进程的代码的某个片段。
进程和线程有啥关系吗?一个进程里有多个线程,一个进程至少的有一个线程。
了解了什么是线程,接下来,我们看一下,线程的三种创建方式。
public class Demo {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
}
}
class MyThread extends Thread {
@Override
public void run() {
System.out.println("线程执行了");
}
}
public class Demo {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread t2 = new Thread(myRunnable);
t2.start();
// t2.run(); 如果直接调用run()方法,其实还是在主线程(main)下在按顺序执行代码。不会创建一个新的线程去,执行run()。
}
}
class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println("线程执行了111");
}
}
上边的方式,虽然也可以实现功能,但是却不那么优雅,所有我们在开发过程中,比较常用以下两种方式。
常用方式:
1)匿名内部类
public class Demo {
public static void main(String[] args) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程执行了");
}
});
t.start();
}
}
2)lambda表达式
public class Demo {
public static void main(String[] args) {
Thread t = new Thread(() -> {
System.out.println("线程执行了");
System.out.println("--------");
});
t.start();
}
}
Callabe一般用于有返回结果的非阻塞的执行方法,Callable这种方式是同步非阻塞的,也就是说,按照在主线程中的代码顺序进行执行,但是当执行到callable代码片段的时候,会创建一个新的线程执行其业务逻辑,但是我们可以再主线程将要结束前,向FutuerTask询问处理结果,由于根据Callable线程处理的业务逻辑耗时不同,此时代码是阻塞的,直到Callable线程任务处理完成。
public class Demo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 1、创建MyCallable
MyCallable myCallable = new MyCallable();
// 2、创建FutureTask,传入Callable
FutureTask<Integer> futureTask = new FutureTask<>(myCallable);
// 3、创建Thread线程
Thread t = new Thread(futureTask);
// 4、启动线程
t.start();
// 5、主线程可以执行一些业务逻辑
System.out.println("main线程执行一些业务逻辑");
// 6、要结果:向futureTask询问,是否处理完成。当执行到这句的时候,会进行阻塞,一直等待到线程处理完成
Integer count = futureTask.get();
System.out.println(count);
}
}
class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int count = 0;
for (int i = 0; i < 100; i++) {
count += i;
}
return count;
}
}
当然,Callable的方式创建线程,我们也可以使用匿名内部类和lambda表达式
1)匿名内部类:
public class Demo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<Integer> futureTask = new FutureTask<>(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
int count = 0;
for (int i = 0; i < 100; i++) {
count += i;
}
return count;
}
});
Thread t1 = new Thread(futureTask);
t1.start();
System.out.println("main线程执行一些业务逻辑");
Integer count = futureTask.get();
System.out.println("count=" + count);
}
}
2)lambda表达式
public class Demo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<Integer> futureTask = new FutureTask<>(() -> {
int count = 0;
for (int i = 0; i < 100; i++) {
count += i;
}
return count;
});
Thread t1 = new Thread(futureTask);
t1.start();
System.out.println("main线程执行一些业务逻辑");
Integer count = futureTask.get();
System.out.println("count=" + count);
}
}
在不考虑线程池创建线程的情况下,通过java创建线程只有这三种方式,可以按照需求来选择使用。同时,注意,尽量使用匿名内部类和lambda表达式来编写代码,使得代码更优雅简洁。