Java多线程基础
一、文章内容
- 1.多线程基本介绍
- 2.多线程hello world
- 3.创建线程的方式
- 4.Runnable介绍
- 5.面试点
注意:如果觉得以上内容简单可跳过本文内容,本文主要针对没怎么了解过多线程的读者
二、正式开始
1. 多线程基本介绍
- 既然大家看到了这篇文章证明大家已经对多线程有了基础的了解; 一句话多线程就是原本由一个人干的活现在找了多个人来同时做(如下图),既然是多个人干那肯定比一个人干的快这也是我们为什么要使用多线程。 既然多线程这么简单那为什么现在面试经常被问还答不上来,最终导致在谈薪资的时候抬不起头;其实在多线程中正是因为多个人做事引入了许多线程之间争抢资源的问题,使得问题变得复杂化。在接下来的文章中我们一起来解决这些问题,并且每篇文章我会提及面试常问的问题方便大家面试。
2.多线程Hello World
- 目标:既然大概了解了什么是多线程,那我们就在mian方法中启动一个新线程线程来不停的打印hello world thread,并且在main方法中也不停的打印hello world main来模拟多个人做事的效果。这里面大家现在需要记住mian也是一个线程他就是来执行我们的代码的线程
在这里我们需要使用到Thread类,在java中Thread就代表线程的意思
2.1 实现步骤
- 创建Thread类, 并在run方法中实现循环打印hello world thread
- 启动Thread线程
- 在main方法中循环打印hello world main
2.2 具体代码
注意一下代码是死循环,程序运行后有输出应立即终止程序
public class ThreadHello {
public static void main(String[] args) {
//1.创建一个新线程
Thread newThread = new Thread(){
@Override
public void run() {
while (true) {
System.out.println("hello world thread");
}
}
};
//2.启动该线程
newThread.start();
//3.在面线程中循环打印
while (true) {
System.out.println("hello world main");
}
}
}
3.线程创建的两种方式
3.1 继承Thread类并实现run方法
既然咱们在helloworld中都可以直接重写Thread的run方法来指定线程执行的任务,那同样的我们也可以自定义类来实现Thread重写run方法(继承方式优点:可以加入更多的任务属性,更灵活的控制线程执行任务)
如:自定义一个线程类MyThread并继承Thread类, 在run方法中打印一千次hello world
public class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("hello world");
}
}
}
//测试自定义线程类是否生效
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start();
}
3.2 通过Runnable方式实现线程
-
Thread的构造方法
public Thread() { init(null, null, "Thread-" + nextThreadNum(), 0); } public Thread(Runnable target) { init(null, target, "Thread-" + nextThreadNum(), 0); }
细心的朋友应该看到了Thread的构造方法可以传入Runnable参数, 简单介绍一下Runnable是什么;
Runnable:它其实就相当于咱们之前直接使用Thread的时候的run方法,更同属的理解就是它是咱们线程去执行的任务,你在Runable的抽象run方法里面写了什么线程在执行的时候就执行什么逻辑。
-
实现目标:
通过传入任务(Runnable)的方式实现打印hello 100次的需求, 一下是使用的匿名内部类的方式同样也可以自己实现Runnable接口去做
public class RunnableThread {
public static void main(String[] args) {
Thread newThread = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("hello world");
}
}
});
newThread.start();
}
}
4.为什么要使用Runnable
在这里我们简单说以下为什么使用Runable: Runnable其实相当于一种策略模式, Thread在执行线程任务时把具体任务逻辑抽象出来由客户端程序员实现;其源码实现如下:
@Override
public void run() {
if (target != null) {
target.run();
}
}
从中我们也可以发现只要我们传入了target就会执行target的run方法中的逻辑。
5. 面试点和坑点
-
面试点1:为什么启动线程是start而不是run
相信大家如果自己写代码可能发现了run和start好像都有效果,其实不然start方法中Thread做了创建线程相关的工作, 而run方法其只是一个普通的方法。
start源代码如下:
public synchronized void start() { if (threadStatus != 0) throw new IllegalThreadStateException(); group.add(this); boolean started = false; try { // 此方法是C++实现的创建线程 start0(); started = true; } finally { try { if (!started) { group.threadStartFailed(this); } } catch (Throwable ignore) { } } }
-
面试点2:创建线程有几种方式(目前咱们了解了两种后续还有)
- 通过继承Thread方法创建县城管
- 通过实现Runable接口创建线程