**一、线程概述**
进程:一个在内存中运行的应用程序。
线程:进程上的一个执行单元,一个进程可以有多个线程。
多进程:在操作系统中同时运行多个程序。
多线程:在同一应用程序中有多个执行单元同时执行
线程的生命周期:—个线程从创建到执行完的整个过程
多线程能解决什么问题:多线程能并发执行程序,提高程序的运行效率。
jvm就是一个进程:
守护线程(垃圾回收),主线程(main函数)
二、如何创建线程对象:
第一种方法:继承Thread类:创建一个线程的子类去继承线程类,因为线程类没有实现类,无法实现功能。同时子类需要重写run()方法。想要线程跑起来,代码必须写在run()方法中。
开启线程用start()方法。
在一个线程中开启另外一个新线程,则新开线程称为该线程的子线程,子线程初始优先级与父线程相同。不过主线程先启动占用了cpu资源,因此主线程总是优于子线程。如下面的main线程与thread线程
public class ThreadDemo01 {public static void main(String[] args) {//创建线程对象,新建状态ThreadImpl thread = new ThreadImpl();//新建状态//开启线程,会让线程进入就绪状态//就绪状态:拥有争夺CPU时间片的权利thread.start();//把遍历操作放一份在主线程for (int i = 0;i<100;i++){System.out.println("主线程"+i);}}}/*** 子类继承Thread后run()必须重写*/class ThreadImpl extends Thread{@Overridepublic void run() {//执行到run方法 多线程处于运行状态for (int i = 0;i<100;i++){//获取当前线程的线程名称System.out.println(currentThread().getName()+"--"+i);}}}

package com.jy.Thread;public class ThreadDemo02 {public static void main(String[] args) {CreateThread createThread1 = new CreateThread();//设置线程名称createThread1.setName("分支线程-1");CreateThread createThread2 = new CreateThread();createThread2.setName("分支线程-2");CreateThread createThread3 = new CreateThread();createThread3.setName("分支线程-3");createThread1.start();createThread2.start();createThread3.start();}}class CreateThread extends Thread{@Overridepublic void run() {for (int i = 0;i<100;i++){//返回的是当前线程的对象Thread thread = Thread.currentThread();//获取当前线程的线程名称System.out.println(thread.getName());}}}
ps:使用睡眠可以使进程进入阻塞状态,阻塞状态会释放cpu时间片
如:Thread.sleep(100);
多线程中主线程与子线程执行的顺序:https://www.yuque.com/wenbusheng-5qk2j/is5soq/qb50a7/edit
第二种方法:实现Runnable接口
/*** 创建线程的第二种方式,实现Runnable接口* 实现接口Runnable的方式来创建线程对象,但要注意所创建的对象new CreateThread01()本身不是线程对象* 创建线程对象:Thread thread1 = new Thread(new CreateThread01());*/public class ThreadDemo03 {public static void main(String[] args) {//创建线程对象Thread thread1 = new Thread(new CreateThread01());Thread thread2 = new Thread(new CreateThread01());Thread thread3 = new Thread(new CreateThread01());thread1.start();thread2.start();thread3.start();}}//虽然实现了Runnable接口,但并不是线程类,只是一个实现类,因为Runnable不是线程接口class CreateThread01 implements Runnable{@Overridepublic void run() {}}
第三种方法:通过匿名内部类重写runnable里的run方法的方式创建线程对象
/*** 通过匿名内部类的方式创建线程对象*/public class ThreadDemo04 {public static void main(String[] args) {//创建线程对象Thread thread = new Thread(new Runnable() {@Overridepublic void run() {}});thread.start();}}
第四种方法 :使用Callable结合Future实现多线程编程。(很重要)
可以获得返回值,前两种没有返回值。
实现方式: **FutureTask futureTask = new FutureTask(new Callable())
FutureTask是继承与Future的**
缺点:在获取线程返回值之前,可以能造成主线程阻塞
package com.jy.Thread;import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.FutureTask;public class ThreadDemo08 {public static void main(String[] args) {//创建一个任务类对象futureTask 不是线程对象FutureTask futureTask = new FutureTask(new Callable() {@Overridepublic Object call() throws Exception {int num = 0;for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName()+" "+i);num+=i;}return num;}});//创建线程对象Thread thread = new Thread(futureTask);thread.setName("t1");thread.start();//获取线程的返回值try {Object o = futureTask.get();System.out.println("t1线程的返回值结果为"+o);} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}System.out.println("主线程结束");}}
上述代码中,在获得返回值num后,才会输出“主线程结束”,即主线程被阻塞。
三、线程的生命周期
1、新建状态:线程对象被创建
2、就绪状态:线程对象调用start方法后就会处于就绪状态,拥有争夺cpu时间片的权利
3、运行状态:当某一个线程争夺到cpu使用权后,就会执行run方法,执行run方法时就处于运行状态
4、阻塞状态:当某一个线程处于运行态时,发生了睡眠sleep或者控制台打印等需要等待的操作,这时线程就会进入阻塞状态,释放cpu使用权
5、死亡状态:当run方法执行结束后,即死亡状态。
**四、线程在jvm内存上的分布
**
1、每一个线程对应一个栈(如主线程main占用一个栈)
2、栈的资源是不共享的
3、堆的资源是共享的,因为new出的对象都在堆中开辟空间,堆只有一个。
**五、线程调度模型
**
抢占式调度模型,优先级高的线程抢到cpu时间片的概率更高。Java就是抢占式。
均分式调度模型,平均分配时间片。
Java中线程优先级默认为5.所有线程争夺CPU的概率相同。
getPriority()方法,获得线程优先级。
**六、yield() 让位方法
**
暂停当前正在执行的线程对象,并执行其他对象
yield()方法的执行会让当前线程从运行状态回到就绪状态。
使用yield()的目的是让相同优先级的线程之间能适当的轮转执行。
但是,实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。
