多线程之旅:认识线程
ok,那么接下来我们走进这个多线程之旅。

当然,我们得认识什么是线程。
那么,认识这个线程之前,我们得先认识下进程先。
那么什么又是进程呢?
进程:是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位。
可以简单来说,进程就是电脑中正在运行的一个独立任务,它有自己需要的资源和执行步骤,可以和其他任务并行运行。
那么这个进程需要占用一定的系统资源,包括内存,CPU时间,文件句柄等,所以比较”重“
接着,我们就引入这个线程。
那什么又是线程呢
线程:
是进程中的一个实体,是CPU调度和分派的基本单位,它是比进程更小的独立运行单位。
这个线程比进程更为轻量,那么我们一般使用这个多线程编程,使我们电脑上的多核心都不闲着,充分利用这个多核心资源。
那么,刚刚可得一个重要的结论。
进程是系统资源分配的基本单位,线程是系统调度的基本单位。
在进程中,线程要么是包含一个,要么是多个,要么就是没有
线程在进程内部中,所以线程是共用进程的资源,即同一份系统资源。
刚刚说到,线程为什么比进程轻量呢?
这是因为线程与进程相比
创建线程,省去了”分配资源“、销毁线程,省去“释放资源",这些过程看着寥寥几个字
但是在系统中,可不是个容易的事,真要执行管理起来,开销是蛮大的。
那么什么又是多线程呢?
多线程:是一种通过并行处理来提升计算机程序运行效率的技术。
那么简单来说,就是干活的人多了
就像是进程得到一份任务了,然后多线程出来了,干活人变多起来,然后可以提高工作效率了。
当然,这里的提高工作效率可以说是,充分利用CPU多核心,”并行执行”任务。
那么要是我提高更多的线程,岂不是执行的更快?
理论上是的!
但是呢,由于我们的CPU核心数目有限,所以不能无休止的添加线程,
所以,一旦我们的线程超出了CPU核心数目,那么此时我们的线程会存在严重的竞争。
当然,解决办法也是简单粗暴的
就是添加更多核心数的CPU!
值得注意的是,如若一个线程执行读的任务操作,一个线程执行写的任务操作,对于同一份数据来说,那么此时就可能出现读的数据不一致的状况,这样的情况呢,就称为“线程安全”
这是多线程编程中非常值得注意的!
讲了,这么多,那么如何来用代码来实现这个多线程编程呢?
这里还要多说一点
这个线程是输入操作系统里的,那么我们操作的话,所以也是操作系统里的。
那么对于java来说呢,这些系统提高的线程API是被封装好了的,我们就可以愉快轻松的使用它啦。
当然,我们接触到的有Linux、windowes,那么对应的它们提高的系统API也是不一样的,甚至可以是说差异巨大呢!
那么进行多线程编程之前呢,那肯定是得创建这个线程先咯。
那么,这里介绍五种较为常见的创建线程的方法
创建线程
1.继承Thread类
class MyThread extends Thread{
//继承Thread来实现线程创建@Overridepublic void run() {
//Thread 中,这里是执行代码逻辑的while (true){
System.out.println("hello thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
public class Demo {
//main方法是一个主线程public static void main(String[] args) {
MyThread myThread=new MyThread();
//这里是开始创建一个线程,然后创建后,会默认调用run()方法//单纯使用run方法,不会创建新线程,// myThread.run();
myThread.start();
//演示下并发执行过程while (true){
System.out.println("hello main");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}代码说明:
我们继承这个Thread类后,要去重写下这个run()方法
那么这个run方法是什么呢?
这个run()可以理解为一个让线程执行的一个个认为来的
里面的代码就是run()方法执行的任务内容
我这里的内容呢,是循环打印hello thread
然后呢,加上一个sleep()方法,给到1000ms,这是为什么呢?因为线程执行速度是蛮快的,所以
加上这个后,待会打印就可以看看其中的执行了,当然,这个sleep()有一个
异常:InterruptedException,所以我们用了try catch处理一下它。
在main方法中
我们实例化这个MyThread类的对象,然后让它去调用这个start()方法。
后面我们同样写了这个循环打印hello main的代码。
这是为什么呢?
这也是写这个也是为了方便我们感受下多线程执行的过程。
那么我们点击运行:

就会出现这样的打印。
注意!注意!
线程的调度是随机的,所以打印的顺序,不一定是从上到下的。
那么,有个疑问。这个hello thread不是run()方法执行的吗。但是main方法中,却没有调用就直接执行到了?
首先我们来理解下这个t.start()方法是干什么的
这个start()方法呢,简单来说呢它的作用就是创建一个线程。
此时,当一个线程创建后,就要执行任务了,那么run()方法里的内容是我们执行任务的代码。
所以,可以说是。run()方法是当线程被创建之后呢,就要执行它了。
所以当我们代码执行完t.start()方法后,run()方法就随之执行了!
2.实现Runnable接口
这个第二个方法就是去实现这个Runnable这个接口,然后去重写里面的run()方法
class MyThread2 implements Runnable{
@Overridepublic void run() {
while (true){
System.out.println("hello world");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
public class Demo2 {
public static void main(String[] args) throws InterruptedException {
//通过实现Runnable来实现线程创建
MyThread2 t=new MyThread2();
Thread thread=new Thread(t);
thread.start();
while (true){
System.out.println("hello main");
Thread.sleep(1000);
}
}
}这里的有些代码,是和代码一差不多的。然后在main方法中
我们实例化我们的MyThread2对象
将对象的引用t作为参数给到Thread中,那么实例化出来的Thread再去调用start()方法,也可以执行代码了,
效果和方法一也是差不多的
3.通过Thread的匿名内部类来实现
public class Demo3 {
//匿名内部类来实现public static void main(String[] args) throws InterruptedException {
//通过Thread的匿名内部类来实现线程创建
Thread t=new Thread(){
@Overridepublic void run() {
while (true){
System.out.println("hello world");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
};
t.start();
while (true){
System.out.println("hello main");
Thread.sleep(1000);
}
}
}在这个匿名内部类中,又重写了run()方法,在这里面执行我们的逻辑。
然后用这个Thread类型的变量接受其返回值,再去调用这个start()方法。
效果和上面那两个差不多的
4.通过实现Runnable的匿名内部类
public static void main(String[] args) throws InterruptedException {
//通过Runnable的匿名内部类来实现线程创建
Runnable runnable=new Runnable() {
@Overridepublic void run() {
while (true){
System.out.println("hello world");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
};
Thread t=new Thread(runnable);
t.start();
while (true){
System.out.println("hello main");
Thread.sleep(1000);
}
}通过实现Runnable的匿名内部类后,我们接着实例化一个Thread对象,把runnable作为参数传给Thread
那么再通过t.start()方法来创建线程
最终效果其实和上述也是差不多的
那么方法四的代码也是可以这样写的,直接在new Thread()里面的参数传入new Runnable的匿名内部类
这样也是可以实现同样效果的
public static void main(String[] args) throws InterruptedException {
//通过Thread的匿名内部类来实现线程创建
Thread t=new Thread(){
@Overridepublic void run() {
while (true){
System.out.println("hello world");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
};
t.start();
while (true){
System.out.println("hello main");
Thread.sleep(1000);
}
}
}5.通过lambda表达式来创建
//lambda表达式创建线程public static void main(String[] args) throws InterruptedException {
Thread t=new Thread(()->{
while (true){
System.out.println("hello world");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
t.start();
while (true){
System.out.println("hello main");
Thread.sleep(1000);
}
}那么线程常见的创建方式,小编就分享到这里。
接下来总结下。
总结:
一:
1.进程是包含线程的
2.进程是系统资源分配的基本单位
线程是系统调度的基本单位
3.线程的不能无节制的创建,不能超过其CPU核心
4.线程的调度是随机,所以线程之间可能会相互影响,引入线程安全问题
5.进程之间不受影响,即一个进程崩溃了,不会影响到其他进程
二.
代码创建线程常用五种方式
1.通过继承Thread类实现
2.通过实现Runnable接口来实现
3.通过实现Thread的匿名内部类实现
4.通过实现Runnable匿名内部类实现
5.通过lambda表达式来实现。