多线程是提升程序性能非常重要的一种方式
使用多线程可以使程序充分利用cpu资源
优点:
1. 系统资源得到更合理的应用
2. 程旭设计更加简洁
3. 程序响应更快,运行效率更高
缺点:
1.需要使用更多的内存空间来支持多线程
2.多线程并发访问的情况可能会影响数据的准确性
3.数据被多线程共享,可能会出现死锁的情况
进程和线程
什么是进程?进程就是计算机正在运行的一个独立的应用程序,进程是一个动态的概念,当我们启动某个应用的时候,进程就产生了,当我们关闭该应用的时候,进程就结束了,进程的生命周期是我们在使用该软件的整个过程。
什么是线程?
线程是组成进程的基本单位,可以完成特定的功能,一个进程是由一个或多个线程组成的,应用程序是静态的,进程和线程是动态的,有创建有销毁,存在时暂时的,不是永久的
进程和线程的区别
进程在运行时拥有独立的内存空间,即每个进程所占有的内存空间都是独立的,互不干扰,线程是共享内存空间的,但是每个线程的执行都是相互独立的,单独的线程是无法执行的,由进程来控制多个线程的执行。
多线程
--------多线程是指在一个进程中,多个线程同时执行,这里所说的同时执行并不是真正意义上的同时执行,系统会为每个线程分配cpu资源,在具体的某个时间段内cpu资源会被一个线程占用,在不同的时间段内由不同的线程来占用cpu资源,所以多个线程还是在交替执行,只不过因为cpu运行速度太快,我们感觉是在同时执行
线程和任务:
线程是去抢占cpu资源的,任务是具体执行业务逻辑的,线程的内部会包含一个任务,线程启动start,当抢占到资源之后,任务就开始执行run
两种方式的区别:
---------1.MyThread,继承Thread类的方式,直接在类中重写run方法,使用的时候,直接实例化MyThread,start即可,因为Thread内部存在Runnable
//1.创建一个Thread的子类
public class MyThread extends Thread {
//2在thread类中的子类中重写run方法,设置线程任务(线程要做什么)
@Override
public void run() {
for (int i = 0; i <20 ; i++) {
System.out.println(i);
}
}
new MyThread().start();
}
2.MyRunnable,实现Runnable接口的方法,在实现类中重写run方法,使用的时候需要先创建Thread对象,并将MyRunnable注入到Thread中,Thread.start.
public class RunnableImpl implements Runnable {
//2.在实现类中重写Runnable接口的run方法,设置线程任务
@Override
public void run() {
for (int i = 0; i <20 ; i++) {
System.out.println(Thread.currentThread().getName()+"---"+i);
}
}
new Thread(new RunnableImpl).start();
}
在实际开发中推荐使用第二种方式
线程的状态
线程共有五种状态,在特定的·情况下,线程可以在不同的状态之间切换,5种状态如下所示
- 创建状态:实例化一个新的线程对象,还未启动。
- 就绪状态:创建好的线程对象调用start方法完成启动,进入线程池等待抢占cpu资源
- 运行状态:线程对象获取cpu资源,在一定的时间内执行任务。
- 阻塞状态:正在运行的线程暂停执行任务,释放所占用的cpu资源,并且解除阻塞状态之后也不能直接回到运行状态,而是重新回到就绪状态,等待获取cpu资源
- 终止状态:线程运行完毕或因为异常导致该线程终止运行
线程合并
合并是指将某个特定的线程加入到当前线程中,合并为一个线程,由两个线程交替执行变成一个线程中的两个子线程顺序执行。
通过·join方法来实现合并,具体如何合并?
线程甲和线程乙,线程甲执行到某个时间点的时候调用线程乙的join方法,则表示当前时间点开始cpu资源被线程乙独占,线程甲进入阻塞状态,直到线程乙执行完毕,线程甲进入就绪状态,等待获取cpu的资源进入运行状态。public class JoinTest implements Runnable { @Override public void run() { for (int i = 0; i <100 ; i++) { System.out.println("thread---"+i); } } public static void main(String[] args) throws InterruptedException { JoinTest joinTest = new JoinTest(); Thread thread = new Thread(joinTest); thread.start(); for (int i = 0; i <100 ; i++) { if (i==10){ thread.join(); } System.out.println(i+"main++++++"); } }
join方法重载,join()表示乙线程执行完毕之后才能执行其他线程,join(long millis)表示乙线程执行millis毫秒之后,无论是否执行完毕,其他线程都可以和他争夺cpu资源
线程礼让
线程礼让是指在特定的某个时间点,让线程暂停抢占cpu资源的行为,运行状态/就绪状态–》阻塞状态,将cpu资源让给其他线程来使用。
假入线程甲和线程乙在交替执行,某个时间点线程甲做出了礼让,所以在这个时间点线程乙拥有cpu资源,执行业务逻辑,,但不代表线程甲一直暂停执行。
线程甲只是在特定的时间节点礼让,过了时间节点,线程甲再次进入就绪状态,和线程乙争夺cpu,线程礼让通过yield方法实现
public class YieldThread09 extends Thread {
@Override
public void run() {
for (int i = 0; i <10 ; i++) {
if (i==5){
yield(); // 线程礼让
}
System.out.println(Thread.currentThread().getName()+"---"+i);
}
}
public static void main(String[] args) {
YieldThread09 thread = new YieldThread09();
thread.setName("线程1");
YieldThread09 thread2 = new YieldThread09();
thread2.setName("线程2");
thread.start();
thread2.start();
}
}
线程中断
有很多种情况会造成线程停止运行:
--------线程执行完毕自动停止
--------线程执行过程中遇到错误抛出异常并停止
--------线程执行过程中根据需求手动停止
Java中实现线程中断有如下几个常用的方法:
- public void stop()
- public void interrupt()
- public boolean isInterrupted()
stop在新版版的JDK中已经不推荐使用,重点关注后两个方法。
interrupt是一个实例方法,当一个线程对象调用该方法时,表示中断当前线程对象,每个线程对象都是通过一个标志位来判断当前是否为中断状态
isInterrupted就是用来获取当前线程对象的标志位:true表示清除了标志位,当前线程已经中断,false表示没有清除标志位,当前对象没有中断。
当一个线程对象出于不同的状态时,中断机制也是不同的: