目录
并发、并行的区别
进程与线程
进程
线程
联系
区别
如何实现线程
继承Thread类,重写run方法
实现Runable接口,实现run方法
callable接口+FutureTask
setPriority线程的优先级
join插入线程
守护线程
线程生命周期
并发:同一时刻,多个指令在单个CPU上交替执行
并行:同一时刻,多个指令在多个CPU上同时执行
假如在多个CPU的电脑上,同一时刻,如果执行指令超过CPU的线程数,那么CPU会对执行指令做交替执行,做并行操作
具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。
是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一些在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。
线程是进程的一部分,一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程
public class ThreadDemo1 extends Thread{@Overridepublic void run() {super.run();for(int i=0;i<10;i++){System.out.println(getName()+i);}}
}public static void main(String[] args){ThreadDemo1 thread1=new ThreadDemo1();thread1.setName("女神");ThreadDemo2 thread2=new ThreadDemo2();thread2.setName("备胎");thread2.setDaemon(true);thread1.start();thread2.start();}
其中setName为给线程取名字,通过getName获取
输出:
可以看到线程都是交替、并行的方式去执行
public class MyRunable implements Runnable{@Overridepublic void run() {for(int i=0;i<100;i++){System.out.println(Thread.currentThread().getName()+"hello5555");}}
}public static void main(String[] args){MyRunable runable1=new MyRunable();MyRunable runable2=new MyRunable();MyRunable runable3=new MyRunable();Thread thread1=new Thread(runable1);Thread thread2=new Thread(runable2);Thread thread3=new Thread(runable3);thread1.setName("线程1");thread2.setName("线程2");thread3.setName("线程3");thread1.start();thread2.start();thread3.start();}
Runable中无法通过getName去获取到线程的名称,但是可以通过Thread.currentThread().getName去获取的
这种可以获取多线程执行的结果
public class MyCallBale implements Callable {//Callable中的泛型为要返回的值的类型@Overridepublic Integer call() throws Exception {int sum=0;for (int i = 0; i < 10; i++) {sum+=i;}return sum;}
}public static void main(String[] args){MyCallBale callBale=new MyCallBale();FutureTask futureTask=new FutureTask<>(callBale);Thread thread=new Thread(futureTask);thread.start();try {System.out.println(futureTask.get());} catch (ExecutionException e) {e.printStackTrace();} catch (InterruptedException e) {e.printStackTrace();}}
输出:
由此,我们也发现继承thread类跟实现runable有本质上的优缺点了
1-10档位,默认是5,数字越大,线程并发的时候有很大的概率会优先执行,来个例子试试
public class ThreadDemo extends Thread{@Overridepublic void run() {super.run();for(int i=0;i<100;i++){System.out.println(getName()+"hello5555");}}
}public static void main(String[] args){ThreadDemo thread1=new ThreadDemo();thread1.setName("线程1");ThreadDemo thread2=new ThreadDemo();thread2.setName("线程2");thread1.setPriority(1);thread2.setPriority(10);thread1.start();thread2.start();}
输出:
可以看到线程2先执行了,但是这种也算是概率性的,比如我在执行了一次,输出:
额,又变成线程1了额,感觉没啥用的这个,这个方法平时不建议使用
在start后执行,会强制插入到其他线程之前执行插入的线程的代码逻辑 Thread.join,实现:
public static void main(String[] args) {ThreadDemo1 thread1=new ThreadDemo1();thread1.setName("女神");ThreadDemo2 thread2=new ThreadDemo2();thread2.setName("备胎");// thread2.setDaemon(true);thread1.start();thread2.start();thread2.join();System.out.println("主线程666");}
这样的话,原本会先执行main线程的 System.out.println("主线程666")的,但是因为thread2线程插入到了主线程之前了,这样的话,就会先执行完线程的逻辑,然后再执行main线程的逻辑
在主线程关闭后无需手动关闭守护线程,因为会自动关闭,避免了麻烦,Java垃圾回收线程就是一个典型的守护线程,简单粗暴的可以理解为所有为线程服务而不涉及资源的线程都能设置为守护线程。举个例子:
public static void main(String[] args) {Thread thread = new Thread(() -> {while (true) {try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("----睡眠一秒-----");}});//默认为false,设置为false代表非守护线程,true为守护线程,守护线程在主方法结束时候结束thread.setDaemon(true);thread.start();try {TimeUnit.SECONDS.sleep(3);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("主线程over");}
输出:
如果设置为false的话,Thread线程就还是照着正常的执行,不会因为设置了守护线程导致中断的问题
输出:
应用场景:
多线程的情况下,主线程在执行结束后,如果有涉及到子线程的话,就可以给它设置为守护线程,其次在守护线程中创建的所有子线程都是守护线程,但是如果是调用join的话,守护线程还是会执行完,然后再执行主线程的内容
新建(start)->就绪(有执行的资格,但是没有抢到CPU的执行权,所以没有执行权利)->运行(抢到CPU的执行权了,去执行代码,但是可能会被其他线程又抢走,所以可能会->就绪)->结束运行状态的可能出现的异常情况:
流程图说明: