一、线程创建的几种方式
常见的创建线程的方式有一下几种:
- 继承Thread类
- 实现Runnable接口
- 实现Callable接口
- 线程池创建
个人理解:
a.通过实现Runnable接口创建线程比继承Thread类创建线程好一点,因为每个类只能继承一个父类,但是可以实现多个接口。
b.Callable接口与Runnable接口的区别如下
-
runnable方式时,多个线程间可以共享实例变量,callable方式则不行
-
runnable方式没有返回值,callable有返回值
-
runnable方式run方法的异常只能在内部消化,callable的call()方法允许抛出异常
c.线程并不是却多越好,因为线程的执行要抢占到CPU的执行权才能执行,如果在单核CPU的情况下,使用多线程反而不如单线程快。
d.线程的周期
- NEW 新建状态,此时线程还没有运行线程中的代码
- RUNNABLE 就绪状态;处于就绪状态的线程并不一定立即运行run方法,必须还要和其他线程竞争CPU时间
- RUNNING 运行状态;线程获得CPU时间后才进入运行状态,开始执行run方法
- BLOCKED 阻塞状态;线程运行过程中会有各种原因来进入阻塞状态,如:调用sleep方法进入休眠;在IO操作中被阻塞;试图得到一个锁,该锁正被其他线程持有;等待某个触发条件.阻塞状态的线程此时没有结束,暂时让出CPU时间给其他线程.
- DEAD 死亡状态;有两个原因导致线程死亡:第一是run方法正常退出自然死亡;第二是一个未捕获的异常终止了run方法使线程死亡.
为了确定线程在当前是否存活着(就是要么是可运行的,要么是被阻塞了),需要使用isAlive方法,如果是可运行或被阻塞,这个方法返回true;如果线程仍旧是new状态且不是可运行的,或者线程死亡了,则返回false。
二、具体创建方式
1.继承Thread类
package com.xingli.threadDemo;
/**
*@ClassName MyThead
*@Description 线程实现的方式第一种:继承thread类
*@Author William
*@Date 2019/8/6 11:44
*@Version 1.0
*/
public class MyTheadTest {
public static void main(String[] args) {
//设置线程名字
Thread.currentThread().setName("主线程:");
MyThread myThread = new MyThread();
myThread.setName("子线程:");
//开启子线程
myThread.start();
//主线程
for(int i = 0;i<5;i++){
System.out.println(Thread.currentThread().getName() + i);
}
}
}
/**
*@description: 创建MyThread继承Thread类
* @author: William
* @date 2019/8/6 11:46
*/
class MyThread extends Thread{
//重写Thread的run方法
@Override
public void run() {
for (int i = 0; i <5 ; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
2.实现Runnable接口
package com.xingli.threadDemo;
/**
*@ClassName MyRunnableTest
*@Description 多线程实现的第二种方式,实现runnable接口
*@Author William
*@Date 2019/8/6 11:51
*@Version 1.0
*/
public class MyRunnableTest {
public static void main(String[] args) {
//设置线程名称
Thread.currentThread().setName("主线程:");
Thread t = new Thread(new MyRunnable());
t.setName("子线程:");
//开启子线程
t.start();
for(int i = 0; i <5;i++){
System.out.println(Thread.currentThread().getName()+":"+ i);
}
}
}
/**
*@description: 创建MyRunnable实现Runnable接口
* @author: William
* @date 2019/8/6 11:52
*/
class MyRunnable implements Runnable {
//重写run方法
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() +":"+ i);
}
}
}
3.实现Callable接口
package com.xingli.threadDemo;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
*@ClassName MyCallableTest
*@Description 多线程实现的第三种方式,实现callable接口
*@Author William
*@Date 2019/8/6 12:03
*@Version 1.0
*/
public class MyCallableTest {
public static void main(String[] args) {
//执行Callable 方式,需要FutureTask 实现实现,用于接收运算结果
FutureTask<Integer> futureTask = new FutureTask<Integer>(new MyCallable(100));
new Thread(futureTask).start();
FutureTask<Integer> futureTask2 = new FutureTask<Integer>(new MyCallable(99));
new Thread(futureTask2).start();
//接收线程运算后的结果,这边有一个要注意的地方,FutureTask获取返回值会阻塞主线程,如果获取不到结果主线程下面的方法不会执行
try {
Integer sum = futureTask.get();
System.out.println(sum);
Integer sum2 = futureTask2.get();
System.out.println(sum2);
for (int i = 0; i < 5; i++) {
System.out.println("主线程结果===");
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
/**
*@description: 创建MyCallable类实现Callable接口
* @author: William
* @date 2019/8/6 12:42
*/
class MyCallable implements Callable<Integer> {
private Integer num ;
/**
*@description: 构造方法,让调用方传递一个int类型的数字过来
* @param num 用户传递数字
* @author: William
* @date 2019/8/6 12:08
*/
public MyCallable(Integer num){
this.num =num;
}
//从写call方法,让方法返回用户传递值%3的结果
@Override
public Integer call() throws Exception {
if(num == null || num<=0){
return null;
}
return num%3;
}
}
4.线程池创建
package com.xingli.threadDemo;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
*@ClassName MyThreadPoolTest
*@Description 多线程实现的第三种方式,实现callable接口
*@Author William
*@Date 2019/8/6 12:41
*@Version 1.0
*/
public class MyThreadPoolTest {
public static void main(String[] args) {
//创建线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
ThreadPool threadPool = new ThreadPool();
for(int i =0;i<5;i++){
//为线程池分配任务
executorService.submit(threadPool);
}
//关闭线程池
executorService.shutdown();
}
}
class ThreadPool implements Runnable {
@Override
public void run() {
for(int i = 0 ;i<5;i++){
System.out.println(Thread.currentThread().getName()+ ":" + i);
}
}
}