这是我参与2022首次更文挑战的第23天,活动详情查看:2022首次更文挑战
前言:更具昨天我们所了解的进程、线程。线程的并行、串行、并发,以及线程的几个状态。那么今天我们来了解一下在JAVA中线程的创建方式和基本用法。
创建方式:
在JAVA中线程的创建方式有三种:通过继承Thread类创建线程类、通过实现Runnable接口创建线程类、通过Callable和Future接口创建线程。
第一种:通过继承Thread类创建线程类
/**
* 通过继承Thread类创建线程类
*/
public class ThreadTest extends Thread{
public static void main(String[] args) {
//创建第一个线程
ThreadTest FirstThreadTest = new ThreadTest();
//创建第二个线程
ThreadTest SecondThreadTest = new ThreadTest();
//启动第一个线程
FirstThreadTest.start();
//启动第二个线程
SecondThreadTest.start();
}
/**
* 线程start后执行run方法
*/
public void run() {
for(int i=0;i < 5;i++) {
//当通过继承Thread类的方式实现多线程时,可以直接使用this获取当前执行的线程
//System.out.println(Thread.currentThread().getName() + ":" + i);
System.out.println(this.getName() + ":" + i);
}
}
}
我们来看一下线程的执行结果:
上图为运行时产生的三种不同情况。可以通过昨天我们讲解的线程的运行方式,从上可以判断为并发形式,在多线程下是存在资源竞争(抢占式),抢占的是时间片。
- 时间片:时间片即CPU分配给各个程序的时间,每个线程被分配一个时间段,称作它的时间片,即该进程允许运行的时间,使各个程序从表面上看是同时进行的。如果在时间片结束时进程还在运行,则CPU将被剥夺并分配给另一个进程。如果进程在时间片结束前阻塞或结束,则CPU当即进行切换。而不会造成CPU资源浪费。在宏观上:我们可以同时打开多个应用程序,每个程序并行不悖,同时运行。但在微观上:由于只有一个CPU,一次只能处理程序要求的一部分,如何处理公平,一种方法就是引入时间片,每个程序轮流执行。总结:也就是CPU只有一个,他处理事情并不是一起的,运行的原则是:某个程序抢占到了时间片,那就先执行他,这个时间片的抢占就是我们所说的资源竞争。
我们来看一下Thread他的底层,他其实是实现了Runnable接口,从名义上来说,他是Runnable的一个重加工类,其中@FunctionalInterface注解是JDK1.8后的表示为“该类有且只有一个方法”。
第二种:通过实现Runnable接口创建线程类
/**
* 通过实现Runnable接口创建线程类
*/
public class MyRunnable implements Runnable {
public static void main(String[] args) {
MyRunnable thread_target = new MyRunnable();
//创建第一个线程,线程名称为FirstThread
Thread FirstThreadTest = new Thread(thread_target,"FirstThread");
//创建第二个线程,线程名称为SecondThread
Thread SecondThreadTest = new Thread(thread_target,"SecondThread");
//启动第一个线程
FirstThreadTest.start();
//启动第二个线程
SecondThreadTest.start();
}
/**
* 重写Runnable接口中的run方法
*/
@Override
public void run() {
for(int i=0;i < 5;i++) {
System.out.println(Thread.currentThread().getName()+ ":" + i);
}
}
}
我们可以看到Runnable接口中有一个抽象方法run,所以在我们实现Runnable接口后,我就需要对run方法,进行重写。
第三种:通过Callable和Future接口创建线程
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class MyCallableTest {
public static void main(String[] args) {
// 方式一我们创建MyCallable对象使他实现Callable接口
/**
* import java.util.concurrent.Callable;
*
* public class MyCallble implements Callable<Integer> {
* @Override
* public Integer call(){
* int i = 0;
* for ( ; i < 5 ; i++ )
* {
* System.out.println(Thread.currentThread().getName()
* + " i的值:" + i);
* }
* return i;
* }
* }
*/
// Callable<Integer> myCallable = new MyCallble;
FutureTask<Integer> futureTask = new FutureTask<Integer>((Callable<Integer>)()->{
int i = 0;
for ( ; i < 5 ; i++ )
{
System.out.println(Thread.currentThread().getName()
+ " i的值:" + i);
}
// call()方法可以有返回值
return i;
});
for (int i = 0; i < 5; i++) {
new Thread(futureTask , "我就是线程名称:").start();
}
try {
//取得新创建的新线程中的call()方法返回的结果
int sum = futureTask.get();
System.out.println("sum = " + sum);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
从上我们可以看到FutureTask实现了接口RunnableFuture,然后RunnableFuture接口他又实现了Runnable和Future。