目录
1、多线程
1.1、什么是多线程?
多线程(multithreading),是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。具有这种能力的系统包括对称多处理机、多核心处理器以及芯片级多处理或同时多线程处理器。在一个程序中,这些独立运行的程序片段叫作“线程”(Thread),利用它编程的概念就叫作“多线程处理” [1] 。(引用自百度百科)
1.2、什么是并发和并行?
并发:指两个或多个事件在同一个时间段内发生。
并行:指两个或多个事件在同一时刻发生(同时发生)。
在操作系统中,安装了多个程序,并发指的是在一段时间内宏观上有多个程序同时运行,这在单 CPU 系统中,每一时刻只能有一道程序执行,即微观上这些程序是分时的交替运行,只不过是给人的感觉是同时运行,那是因为分时交替运行的时间是非常短的。而在多个 CPU 系统中,则这些可以并发执行的程序便可以分配到多个处理器上(CPU),实现多任务并行执行,即利用每个处理器来处理一个可以并发执行的程序,这样多个程序便可以同时执行。目前电脑市场上说的多核 CPU,便是多核处理器,核越多,并行处理的程序越多,能大大的提高电脑运行的效率。
注意:单核处理器的计算机肯定是不能并行的处理多个任务的,只能是多个任务在单个CPU上并发运行。同理,线程也是一样的,从宏观角度上理解线程是并行运行的,但是从微观角度上分析却是串行运行的,即一个线程一个线程的去运行,当系统只有一个CPU时,线程会以某种顺序执行多个线程,我们把这种情况称之为线程调度。
1.3、线程与进程
什么是进程?
进程概述:是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程;进程也是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个进程从创建、运行到消亡的过程。
进程:就是正在运行的程序。通过任务管理器我们就看到了进程的存在。而通过观察,我们发现只有运行的程序才会出现进程。进程是系统进行资源分配和调用的独立单位。每一个进程都有它自己的内存空间和系统资源。
什么是线程?
概述:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。
线程:在同一个进程内又可以执行多个任务,而这每一个任务我就可以看出是一个线程。是程序的执行单元,执行路径。是程序使用CPU的最基本单位。
单线程:如果程序只有一条执行路径。
多线程:如果程序有多条执行路径。线程是进程是最基本的执行单位。
多线程存在的意义
多线程的存在,不是提高程序的执行速度。其实是为了提高应用程序的使用率。
总结:一个程序运行后至少有一个进程,一个进程中可以包含多个线程。
2、多线程的创建
2.1、继承Thread类
实现步骤:
1、定义Thread类的子类,并重写该类的run()方法,该run()方法的方法体就代表了线程需要完成的任务,因此把run()方法称为线程执行体。
2、创建Thread子类的实例,即创建了线程对象。
3、调用线程对象的start()方法来启动该线程。
代码演示:
//继承Thread类
public class MyThread extends Thread {
//重写run方法 并实现循环打印helloworld
@Override
public void run() {
for (int i = 0; i < 10; i++) {
//通过getName方法可以获取到当前线程的名字
System.out.println(getName()+"helloWorld"+i);
}
}
}
public class MyThreadDemo {
public static void main(String[] args) {
//创建Thread类的子类对象
MyThread my1=new MyThread();
MyThread my2=new MyThread();
//给子类对象赋名字
my1.setName("线程一");
my2.setName("线程二");
//开启线程
my1.start();
my2.start();
}
}
注意事项:不能通过Thread类子类对象调用run方法的形式启动线程,这样并不会启动线程,只是一个简单的方法调用,而是去调用start方法。因为start方法会使线程进入就绪状态,JVM去调用run方法实现线程启动。还有一点就是一个Thread子类对象只能启动一次线程,不能重复启动,否则报错IllegalThreadStateException 非法的线程态态异常。
MyThread my = new MyThread();
//这不是启动线程,相当于调了run()方法,只是普通调用
my.run();
//IllegalThreadStateException 非法的线程态态异常
//为什么呢? 因为你启动两次,并不是两个线程
my.start();
my.start();
2.2、实现Runnable接口
实现步骤:
1、定义Runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。
2、创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。
3、调用线程对象的start()方法来启动线程。
代码演示
public class MyRunnable implements Runnable {
//定义一个共有资源num
private int num=20;
@Override
public void run() {
for (int i = 1; i <=100 ; i++) {
//判断共有资源是否为0,如果不为0,继续输出
if(num>0){
System.out.println(Thread.currentThread().getName()+":"+(num--));
}
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
//定义Runnable接口的实现类对象
MyRunnable myRunnable=new MyRunnable();
//创建Thread类对象传入实现类对象,并给每个线程赋名字
Thread t1=new Thread(myRunnable,"线程1");
Thread t2=new Thread(myRunnable,"线程2");
Thread t3=new Thread(myRunnable,"线程3");
Thread t4=new Thread(myRunnable,"线程4");
//启动线程
t1.start();
t2.start();
t3.start();
t4.start();
}
}
3、Thread类和Runnable接口的区别
1、Runnable接口的话,可以避免单继承的局限性,具有较强的健壮性。
2、Runnable可以实现资源的共享,同时处理同一资源。
3、Thread类的线程间都是独立运行的,资源不共享。
4、继承Thread类不再被其他类继承(java中类不存在多继承)。
4、线程状态