83.多线程
什么是线程:
-
线程右进程创建的,是进程的一个实体
-
一个进程可以有多个线程
并发:同一个时刻,多个任务交替执行,造成一种貌似同时的错觉
并行:同一个时刻,多个任务同时执行,多核CPU可以实现。可能并发和并行同时存在
通过Java查询电脑的CPU个数:
public class HelloJava { public static void main(String[] args) { Runtime runtime = Runtime.getRuntime(); //获取当前电脑的cpu数量 int cpuNums = runtime.availableProcessors(); System.out.println("当前电脑的cpu个数=" + cpuNums); } }
线程基本使用
创建线程的两种方法:
-
继承Thread类,重写run方法
-
实现Runnable接口,重写run方法
注意:若主线程结束了,但还有子线程在运行,就不会导致整个线程关闭
为什么要用cat.start(),而不是直接用cat.run()呢?
run就是一个普通方法,没有真正启动一个线程,就会把run方法执行完毕,才向下执行 ,相当于串行化执行
start才会真正的启动一个线程
(1) public synchronized void start(){ start0(); } (2) //start0()是本地方法,是JVM调用,底层是C/C++实现 //真正达到多线程效果的,是start(),而不是run() private native void start0(); //start()调用start0()方法后,该线程不一定会立马执行,只是将线程变成了可运行状态。具体什么时候执行,取决于CPU,由CPU统一调度
通过Runnable接口实现线程
因为Java是单继承的,在一个类可能已经继承了某个父类,这时在用继承Thread方法来创建线程显然不可行
所以提供了另一个方式创建线程,就是通过实现Runnable接口
Runnable没有start()方法,怎么办呢?
//创建一个Thread对象,把dog对象(实现Runnable),放入Thread Thread thread = new Thread(dog); thread.start(); //这里调用start()方法,启动线程,并带动run方法 //这里是因为底层使用了 代理模式,逻辑如下 //线程代理类,模拟了一个极简的Thread class ThreadProxy implements Runnable{ private Runnable target = null; @Override public void run(){ if(target != null){ target.run();//动态绑定 } } public ThreadProxy(Runnable target){ this.target = target } public void start(){ start0(); } public void start0(){ run(); } }
多线程案例:
public class HelloJava { public static void main(String[] args) { T1 t1 = new T1(); T2 t2 = new T2(); Thread thread1 = new Thread(t1); Thread thread2 = new Thread(t2); thread1.start(); thread2.start(); } } class T1 implements Runnable{ int count = 0; @Override public void run() { while (true) { //每隔一秒,输出“Hello World”,10次 System.out.println("hello world " + (++count)); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } if (count == 10){ break; } } } } class T2 implements Runnable{ int count = 0; @Override public void run() { while (true) { //每隔一秒,输出“hi”,五次 System.out.println("hi " + (++count)); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } if (count == 5){ break; } } } }
通知线程退出:
-
当线程完成任务后,会自动退出
-
还可以通过使用变量来控制run方法退出的方式停止线程,即通知方式
//需求,启动一个线程t,要求在main线程中去停止线程t public class HelloJava { public static void main(String[] args) throws InterruptedException { T t = new T(); t.start(); //如果希望主线程控制t线程的终止,必须可以修改loop //让t退出run方法,从而终止t线程 ->通知方式 //让主线程休眠10秒,再通知t线程退出 Thread.sleep(1000*10); t.setLoop(false); } } class T extends Thread{ //设置一个控制变量 private boolean loop = true; int count = 0; @Override public void run() { while (loop) { try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("T 运行中......" + (++count)); } } public void setLoop(boolean loop) { this.loop = loop; } }
线程常用方法
1.setName 设置线程名称,使之与参数 name 相同
2.getName 返回该线程的名称
3.start 使该下暗藏卡爱上执行,Java虚拟机底层调用该线程的start0方法
4.run 调用线程对象run方法
5.setProiority 更改线程的优先级
6.getProiority 获取线程的优先级
7.sleep 在指定的毫秒数内让当前正在执行的线程休眠
8.interrupt 中断线程
interrupt中断线程,但没有真正的结束线程,所以一般用于中断正在休眠的线程