文章内容主要来源为元动力科技,我个人觉得非常好,这里是他们的网站
网站链接
线程:一个正在执行中的程序就是一个进程,系统会为这个进程发配独立的【内存资源】。进程是程序的一次执行过程,它有自己独立的生命周期,它会在启动程序时产生,运行程序时存在,关闭程序时消亡。
进程:线程是由进程创建的,是进程的一个实体,是具体干活的人,一个进程可能有多个线程。线程不独立分配内存,而是共享进程的内存资源,线程可以共享cpu的计算资源。
知识补充:
物理CPU就是计算机上实际安装的CPU,就是主板上实际插入的CPU数量。
物理CPU内核,每颗物理CPU可以有1个或者多个物理内核,通常每颗物理CPU的内核数都是固定的,单核CPU就是有1个物理内核,我这个电脑有八颗
逻辑CPU,操作系统可以使用逻辑CPU来模拟真实CPU。在没有多核处理器的时候,一个物理CPU只能有一个物理内核,而现在有了多核技术,一个物理CPU可以有多个物理内核,可以把一个CPU当作多个CPU使用,没有开启超线程时,逻辑CPU的个数就是总的CPU物理内核数。然而开启超线程后,逻辑CPU的个数就是总的CPU物理内核数的两倍。
(1.)继承Thread类重写run方法:run和start【文章】
步骤:
1.定义类继承Thread;
2.重写Thread类中的run方法;(目的:将自定义代码存储在run方法,让线程运行)
3.调用线程的start方法:(该方法有两步:启动线程,调用run方法)
package com.itheima.example18; public class UseThread { public static void main(String[] args) { System.out.println(1); new MyTask().start();//创建新线程 System.out.println(3); try { Thread.sleep(100); //主线程睡,在此过程中新线程开始执行,输出2 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(4); } static class MyTask extends Thread{ @Override public void run(){ System.out.println(2);//这里的run 是这个线程只要一开始就会开始运行,所以就会自然而然的输出2了 } } }
输出结果:
(2.)实现Runnable接口:(Runnable和Thread的区别)【文章】
步骤:
1.创建任务: 创建类实现Runnable接口
2.使用Thread 为这个任务分配线程
3.调用线程的start方法
package com.itheima.example18; public class UseRunnable { public static void main(String[] args) { System.out.println(1); new Thread(new Task()).start(); System.out.println(3); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(4); } static class Task implements Runnable{//实现Runnable接口 public void run(){ System.out.println(2); } } }
(3.) 使用Lmmabda表达式:
package com.itheima.example18; public class UseRunnable { public static void main(String[] args) { System.out.println(1); new Thread(()-> System.out.println(2)).start(); System.out.println(3); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(4); } }
(4.)有返回值的线程:
package com.itheima.example18; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; import java.util.concurrent.Callable; public class UseCallable { public static void main(String[] args) throws ExecutionException, InterruptedException { System.out.println(2); FutureTask<Integer> futureTask=new FutureTask<>(new Task()); System.out.println(3); new Thread(futureTask).start(); System.out.println(4); int result=futureTask.get(); //这是一个阻塞的方法,意思就是,这个方法会一直等,主线程会一直等待,这个线程执行完成之后并有了返回值,才会继续执行。 System.out.println(5); System.out.println(result); System.out.println(6); } static class Task implements Callable <Integer>{ public Integer call() throws Exception{ Thread.sleep(2000); return 1; } } }
输出结果:
多线程计算从一加到一亿:
代码:
package com.itheima.example18; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; import java.util.concurrent.Callable; public class UseCallable implements Callable<Long>{ private int from; private int to; public UseCallable() { }//无参构造 public UseCallable(int from, int to) { this.from = from; this.to = to; }//有参构造器 @Override public Long call() throws Exception{ Long res=0L; for(int i=from;i<to;i++){ res+=i; } return res; } public static void main(String[] args) throws ExecutionException, InterruptedException { //单线程计算 long start=System.currentTimeMillis();//获取时间 long res=0L; for(int i=0; i<100000000;i++){ res+=i; } long end=System.currentTimeMillis(); System.out.println(end-start); System.out.println(res); //多线程计算 start=System.currentTimeMillis(); res=0L; FutureTask[] futureTasks=new FutureTask[5]; for(int i=0; i<5;i++){//分成五个线程来计算 FutureTask<Long> task=new FutureTask<>(new UseCallable(i*20000000,(i+1)*20000000)); new Thread(task).start(); futureTasks[i]=task; } for(int i=0;i<5;i++) { Long sum=(long)futureTasks[i].get(); res+=sum; } end=System.currentTimeMillis(); System.out.println(end-start); System.out.println(res); } }
Java提供两种类型的线程:用户线程 和守护程序线程 。守护线程旨在为用户线程提供服务,并且仅在用户线程运行时才需要
守护线程对于后台支持任务非常有用,例如垃圾收集,释放未使用对象的内存以及从缓存中删除不需要的条目。
优先级:守护线程的优先级比较低,用于为系统中的其它对象和线程提供服务。
设置:通过setDaemon(true)来设置线程为“守护线程”;将一个用户线程设置为
守护线程的方式是在 线程对象创建 之前 用线程对象的setDaemon方法。
package com.itheima.example18; public class Deamo { public static void main(String[] args) { Thread T1=new Thread(()->{ int count=10; Thread T2=new Thread(()->{ while(true){ ThreadUtils.sleep(300); System.out.println("我是个守护线程!"); } }); T2.setDaemon(true);//将T2设置为守护线程 T2.start(); while(count>0){ ThreadUtils.sleep(200); System.out.println("我是用户线程"); count--; } System.out.println("用户线程结束----------------------------------------------"); }); //T1.setDaemon(true); T1.start(); } }
输出结果:
我们在Thread类中发现了一个内部枚举类,这个State就可以表示一个线程的生命周期:
我找不到这个state(菜狗),所以大家可以看下边链接里的的文章。
文章链接
下面我们弄一下join方法
package com.itheima.example18; public class Text { public static void main(String[] args) { Thread t1=new Thread(()->{ for(int i=0;i<10;i++){ ThreadUtils.sleep(300); System.out.println("这是线程1------------"); } }); Thread t2=new Thread(()->{ for(int i=0;i<10;i++){ ThreadUtils.sleep(300); System.out.println("这是线程2------------"); } }); t1.start(); t2.start(); try { t1.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("____--------------------------____"); } }
输出结果:
join()方法的本意是阻塞主线程,直到t1线程和t2线程执行完毕后继续执行主线程;