多线程的基础知识以及应用
一、什么是多线程
1.1、什么是进程
进程我们可以理解为程序的基本执行实体,我们打开任务管理器,每个软件的运行就是1个进程。
1.2、多线程
线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。
例如我们打开360软件,360软件本身就是1个进程,360里面的木马查杀、电脑清理、系统修复、优化加速等功能就是多个线程
总结:
多线程就是应用软件中相互独立,可以同时运行的功能
二、创建线程的三种方式
2.1、继承thread类重写run方法
package cn.itcast.thread;public class MyThread extends Thread{@Overridepublic void run() {for (int i = 0; i <100 ; i++) {String name = getName();System.out.println("我是:" + name);}}
}
然后在main方法中执行,如果在test方法中执行,可能出现线程执行时间过短,无法展示完整的结果
package cn.itcast.thread;import org.junit.Test;import java.util.Calendar;
import java.util.Date;public class Test1 {//@Test//public void test1() {// MyThread myThread1=new MyThread();// myThread1.setName("线程1");// myThread1.start();// MyThread myThread2=new MyThread();// myThread2.setName("线程2");// myThread2.start();////}public static void main(String[] args) {MyThread myThread1=new MyThread();myThread1.setName("线程1");myThread1.start();MyThread myThread2=new MyThread();myThread2.setName("线程2");myThread2.start();}}
2.2、实现Runnable接口,重写run方法
package cn.itcast.thread.run;public class MyRun implements Runnable{@Overridepublic void run() {for (int i = 0; i < 100; i++) {Thread thread = Thread.currentThread();System.out.println("我是:"+thread.getName());}}
}
然后在main方法中执行
package cn.itcast.thread.run;import cn.itcast.thread.MyThread;
import org.junit.Test;public class Test1 {//@Test//public void test1() {// //要执行的线程任务// MyRun myRun=new MyRun();// //创建线程对象// Thread t1=new Thread(myRun);// t1.setName("线程1");// Thread t2=new Thread(myRun);// t2.setName("线程2");// //开启线程// t1.start();// t2.start();////}public static void main(String[] args) {//要执行的线程任务MyRun myRun=new MyRun();//创建线程对象Thread t1=new Thread(myRun);t1.setName("线程1");Thread t2=new Thread(myRun);t2.setName("线程2");//开启线程t1.start();t2.start();}}
2.3、实现Callable接口重写call方法
package cn.itcast.thread.call;import java.util.concurrent.Callable;public class MyCall implements Callable<Integer> {@Overridepublic Integer call() throws Exception {Integer sum=0;for (int i = 0; i <=100; i++) {sum=sum+i;}return sum;}
}
然后在main方法中执行
package cn.itcast.thread.call;import cn.itcast.thread.run.MyRun;
import org.junit.Test;import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;public class Test1 {//@Test//public void test1() throws ExecutionException, InterruptedException {// //要执行的线程任务// MyCall myCall=new MyCall();// //FutureTask对象用来管理多线程运行的结果// FutureTask<Integer>futureTask=new FutureTask<>(myCall);// //创建线程对象// Thread t1=new Thread(futureTask);// //开启线程// t1.start();// //拿到多线程的运行结果// Integer result = futureTask.get();// System.out.println(result);////}public static void main(String[] args) throws ExecutionException, InterruptedException {//要执行的线程任务MyCall myCall=new MyCall();//FutureTask对象用来管理多线程运行的结果FutureTask<Integer>futureTask=new FutureTask<>(myCall);//创建线程对象Thread t1=new Thread(futureTask);//开启线程t1.start();//拿到多线程的运行结果Integer result = futureTask.get();System.out.println(result);}}
三种方法具体的差别,以及thread类的常用API看之前写的文章
并发和并行的概念也看之前的文章
JAVA基础进阶(十一)-CSDN博客
三、守护线程
守护线程指的是非守护线程全部结束后,守护线程一定结束。
创建线程1
package cn.itcast.thread.protect;public class MyThread1 extends Thread{@Overridepublic void run() {for (int i = 0; i <10 ; i++) {String name = getName();System.out.println(name + "@"+i);}}
}
创建线程2
package cn.itcast.thread.protect;public class MyThread2 extends Thread{@Overridepublic void run() {for (int i = 0; i <100 ; i++) {String name = getName();System.out.println(name + "@"+i);}}
}
在main方法中将MyThread2线程设置为守护线程:myThread2.setDaemon(true);
package cn.itcast.thread.protect;import cn.itcast.thread.MyThread;
import org.junit.Test;public class Test1 {//@Test//public void test1() {// MyThread1 myThread1=new MyThread1();// myThread1.setName("女神");// MyThread2 myThread2=new MyThread2();// myThread2.setName("备胎");// myThread2.setDaemon(true);// myThread1.start();// myThread2.start();//}public static void main(String[] args) {MyThread1 myThread1=new MyThread1();myThread1.setName("女神");MyThread2 myThread2=new MyThread2();myThread2.setName("备胎");myThread2.setDaemon(true);myThread1.start();myThread2.start();}}
得到最终结果:
当非守护线程myThread1结束后,守护线程myThread2执行一段时间后会立马结束,不会执行完,myThread2执行完最后应该是99,只执行到了11
应用场景:打开qq聊天,同时传输文件,qq聊天就相当于非守护线程,传输文件就相当于守护线程,当关闭聊天框,传输文件也会随之关闭
四、线程的生命周期
4.1、创建线程
1、使用start()方法创建线程后,线程就处于就绪状态,此时线程有执行资格,但是没有执行权,因为需要和其他的线程不停抢占CPU的执行权
2、当抢到CPU的执行权后,此时线程既有执行资格又有执行权,就能执行线程中的代码,此时线程处于运行状态。
3、如果此时CPU的执行权被其他线程抢走,线程就又会回到就绪状态,又或者线程被sleep()方法或者其他方法阻塞,就既没有执行资格也没有执行权,处于阻塞状态,如果以上两种情况都没有出现,那么线程就能执行完毕,线程就会死亡变成垃圾。