目录
1.认识线程
1.1概念
1)线程是什么?
线程就是一个执行流,每个线程可以按照顺序执行自己的代码,多个线程之间“同时”执行着多份代码。
在讲多线程之前,我想先讲一下在我们生活当中用到线程的一种实例。
设想一下如果我们要去超市买东西,需要购买洗发水,面包和鱼三种生活用品,但是这些生活用品在超市的不同楼层,如果我们是一个人去逛超市,那么就需要将这三个地方分别跑一趟,但是这个时候,如果有朋友或者家人和我们一同前去,那么只需要分别去这三个地方就可以了,相当于是三个人分别完成了不同的事务,但是本质上这三个人都是为了逛超市购买商品这一件事情进行服务的。
此时,这种情况就可以被我们称之为多线程,也就是将一个大任务划分为一个个子任务,交给不同的执行流进行执行,而朋友或者家人是我们叫来一同逛超市的,我们我们自己也可以被称之为“主线程”(Main Thread)。
2)线程存在的意义?
一方面,在单核cpu发展的途中出现了算力瓶颈,因此就需要多核cpu,而并发编程能更充分的利用多核cpu的资源,另一方面,在有些场景中需要“等待IO”,因此让IO在等待的过程中去做一些其他的事情,也需要用到并发编程的思想。
但是这又会涉及到另一个问题,就是多进程和多线程都可以进行并发编程,但是为什么不适用多进程而选择使用多线程呢?
是因为,创建进程比创建线程更慢,销毁一个进程也比销毁一个线程消耗的资源大,并且在线程调度的时候也比进程要快。
3)线程和进程的区别?
上面又引出了一个词叫做进程。那么进程和线程的关系又是什么呢?
说的通俗一点,一个进程是由多个线程所组成的,并且这些线程是共享同一份资源的。并且没一个进程之间都至少有一个主线程存在。
进程又是系统分配资源的最小单位,而线程则是系统调度的最小单位。
他俩之间的关系可以用以下这张图来表示:
4)Java线程和操作系统线程的关系
线程是作为操作系统中的概念,操作系统内核实现了线程这样的机制,并且对用户层提供了以下API供用户使用。而在Java标准库中Thread类可以视为是对操作系统提供的API进行了进一步的抽象和封装。
1.2创建线程
为了创建线程,提供了以下5种方法来创建一个线程,只展示了5种,但是并不是只有5种。
1)继承Thread类
package Thread;
/**
* Created with IntelliJ IDEA
* Descripton继承Thread类
* User:18041
* Date:2024-02-28
* Time:22:47
*/
//继承Thread类来创建一个线程类
class MyThread extends Thread{
@Override
public void run() {
System.out.println("这里是线程运行代码");
}
}
public class Demo1 {
public static void main(String[] args) {
MyThread t=new MyThread(); //创建MyThread类的实例
t.start(); //调用start方法启动线程
}
}
2)实现Runnable接口
class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println("这里是线程运行的代码");
}
}
public class Demo2 {
public static void main(String[] args) {
Thread t=new Thread(new MyRunnable());
t.start();
}
}
3)继承Thread类,使用匿名内部类
public class Demo3 {
public static void main(String[] args) {
Thread t1=new Thread(){
@Override
public void run() {
System.out.println("这是匿名内部类创建Thread子类对象");
}
};
t1.start();
}
}
4)实现Runnable接口,使用匿名内部类
public class Demo4 {
public static void main(String[] args) {
Thread t2=new Thread(new Runnable() {
@Override
public void run() {
System.out.println("使用匿名内部类创建Runnable子对象");
}
});
t2.start();
}
}
5)使用lambda表达式创建Runnable对象
public class Demo5 {
public static void main(String[] args) {
Thread t3=new Thread(()->
System.out.println("使用lambda表达式创建Thread子对象"));
Thread t4=new Thread(()->{
System.out.println("使用lambda表达式创建Thread子对象");
});
t3.start();
t4.start();
}
}
1.3 多线程的优势-增加运行速度
可以观察多线程在一些场合下是可以提高程序的整体运行效率的。
. 使用system.nanoTime()可以记录当前系统的纳秒级时间戳。
. serial串行的完成一系列运算.concurrency使用两个线程并行的完成同样的运算。
下方是一段示例代码
这段代码使用了Thread的join方法,join方法在某一个线程中被调用之后,该线程必须等待Thread的对象执行完自己线程的代码以后才可以执行接下来的代码。
public class Demo6 {
public static final long count=10_0000_0000;
public static void main(String[] args) throws InterruptedException {
concurrency();
serial();
}
public static void concurrency()throws InterruptedException{
long begin=System.nanoTime();
//利用一个线程计算a的值
Thread thread=new Thread(new Runnable() {
@Override
public void run() {
int a=0;
for(long i=0;i<count;i++){
a--;
}
}
});
thread.start();
//主线程计算b的值
int b=0;
for(long i=0;i<count;i++){
b--;
}
//等待thread线程运行结束
thread.join();
//统计耗时
long end=System.nanoTime();
double ms=(end-begin)*1.0/1000/1000;
System.out.printf("并发: %f 毫秒%n",ms);
}
private static void serial(){
long begin=System.nanoTime();
int a=0;
for(long i=0;i<count;i++){
a--;
}
int b=0;
for (long i=0;i<count;i++){
b--;
}
long end=System.nanoTime();
double ms=(end-begin)*1.0/1000/1000;
System.out.printf("串行: %f 毫秒%n",ms);
}
}
运行结果