线程
1.线程是程序执行中的一个单一控制流程,是程序执行的最小单位,是处理调度分派的基本单位。
2.一个标准线程由线程ID,当前指令指针,寄存器和堆栈组成
3.每个线程都有其各自的栈内存 ,堆,多个线程共享一个堆内存
进程
1.具有一定独立功能的程序在一个数据集上的一次动态执行过程,是操作系统进行资源分配和调度的一个独立单位
,是应用程序运行的载体
。
多线程
一个进程中有多个线程,多个线程在表面上看来是同时进行的,但是实际上是多个线程在不断抢夺CPU执行权,交替执行,只不过用时很短,又称分时复用
主线程
一个进程自带一个线程,称为主线程
子线程
一个线程除了主线程,其余的都是子线程
前台线程与后台线程
1. 后台线程会随着主线程(main线程)的结束而结束,但是前台进程则不会(如果main线程先于前台进程结束,前台进程仍然会执行);或者说,只要有一个前台线程未退出,进程就不会终止。;
2. 默认情况下,程序员创建的线程是用户线程;用setDaemon(true)可以设置线程为后台线程;而用isDaemon( )则可以判断一个线程是前台线程还是后台线程;
3. jvm的垃圾回收器其实就是一个后台线程;
4. setDaemon函数必须在start函数之前设定,否则会抛出IllegalThreadStateException异常;
5.所有的“非后台线程”结束时,程序也就终止了,同时会杀死进程中所有后台线程:main就是一个非后台线程;
6.后台线程创建的子线程也是后台线程。
守护线程
守护线程--也称“服务线程”,在没有用户线程可服务时会自动离开。优先级:守护线程的优先级比较低,用于为系统中的其它对象和线程提供服务。
当JVM中还有线程在执行的时候是不会退出的,意思是非守护线程会“阻止”JVM退出。守护线程不会这样,当JVM中所有非守护线程执行完毕后就会退出执行,并不会考虑是否还有守护线程未执行完毕。JVM中的GC线程就是守护线程,这样设计目的很明确,当你所有的程序都执行完毕了,留着这个GC线程就没有任何意义了
同步
多个线程在执行时先执行一个再执行另一个,不能同时操作一个数据
异步
多个线程同时执行,互不干扰
线程与进程
联系
1.一个线程只能属性一个进程,而一个进程可以有多个线程,但至少有一个线程
2.资源分配给进程,同一进程的所有线程共享该进程的所有资源
3.线程在执行过程中,需要协作同步。不同进程的线程间要利用消息通信方法实现同步。线程是指进程内的一个执行单元,也是进程内的可调度实体。
4.一个进程至少要保证有一个前台线程存活,否则该进行也将被销毁
区别
1.线程是程序执行的最小单位,而进程是操作系统分配资源的最小单位
2.一个线程由一个多个线程组成,线程是一个进程中代码的不同执行路线
3.进程之间相互独立,但同一进程下的各个线程之间共享程序的内存空间(包括代码段,数据集,堆等)及一些进程级的资源(如打开文件和信号等)
一个进程内的线程在其他进程不可见;
4.线程上下文切换比进程上下文切换要快得多。
线程的创建
方案1
查看源码,可以看到Thread 是个普通类,说明可以直接new出来,但是直接new的话run方法没重写,没啥用,所以需要个继承的
方式1 使用一个类继承于Thread,在该类中重写run方法
public class work {
public static void main(String[] args) {
Namer namer = new Namer();
namer.start();//启动线程
}
}
class Namer extends Thread {//创建一个类,继承于Thread
@Override
public void run() {//重写run方法
// TODO Auto-generated method stub
System.out.println("创建线程");
super.run();
}
}
方式2 使用匿名内部类形式创建线程对象
Thread thread = new Thread() {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("匿名内部类创的");
super.run();
}
};
thread.start();
方案2
使用Runnable
可以看到传入任务对象
查看Runnable发现其为接口
将线程任务(Runnable)与线程(Thread)分开
方式1
创建线程任务对象,在创建线程时传入线程任务对象
1.创建一个类,完成Runnable接口
2.重写run方法
3. 创建该类对象,该类对象就是线程任务对象
4.创建线程对象,传入线程任务对象
public class work2 {
public static void main(String[] args) {
Namber1 namber1 = new Namber1();//创建线程任务
Thread thread = new Thread(namber1);//传入线程
thread.start();//运行
}
}
class Namber1 implements Runnable{
@Override
public void run() {//实现接口,实现run方法
// TODO Auto-generated method stub
System.out.println("创一个线程任务");
}
}
方式2
使用匿名内部类的形式创建线程任务对象
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("匿名内部类创的");
}
});
thread2.start();
案例:创建三个卖票的,让他们同时卖1000张票
public class Test9 {
public static void main(String[] args) {
MyPiao myPiao = new MyPiao();
Thread thread = new Thread(myPiao,"窗口1");
Thread thread2 = new Thread(myPiao,"窗口2");
Thread thread3 = new Thread(myPiao,"窗口3");
thread.start();
thread2.start();
thread3.start();
}
}
class MyPiao implements Runnable{
private int num=1000;
public MyPiao() {
super();
// TODO Auto-generated constructor stub
}
@Override
public void run() {
// TODO Auto-generated method stub
while (num>0) {
Thread thread = Thread.currentThread();
String nameString =thread.getName();
num--;
System.out.println(nameString+"卖了第"+num+"张");
}
}
}
线程的方法
启动
语法:线程对象.start();
使用线程对象调用start方法才会开启新的执行路径,如果使用对象调用run相当于调方法,并没有开启新的执行路径
消亡
语法:
线程对象.stop();可以让线程停止,但是方法已经过时
线程对象.destroy();是让程序崩溃,该方法也过时了
有斜杠的都过时了,
不过线程在执行完run方法中的代码之后就会等待系统回收,一般开启线程后我们将不在管理,等待run执行完毕就会自动销毁。
线程已经启动将不受控制
获取当前线程
语法:Thread 当前线程对象 = Thread.currentThread();
在那个线程中使用该方法,就是获取那个线程对象
package demo2;
public class work3 {
public static void main(String[] args) {
Test test = new Test();
Thread thread = new Thread(test);
Thread thread2 = new Thread(test);
System.out.println("thread名字:"+thread.getName());//获取名字
System.out.println("thread2名字:"+thread2.getName());//获取名字
thread.start();
thread2.start();
}
}
class Test implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
Thread thread=Thread.currentThread();//运行那个获取那个
for (int i = 0; i < 10; i++) {
String string=thread.getName();//获取一下名字
System.out.println(i+"是"+string+"执行的");//看看是那个线程运行的
}
}
}
名称
设置名称:
方法一:
在传入时传入线程
方法二
在线程启动前通过setName设置线程名称
线程对象.setName(线程名称);
Thread thread = new Thread(test,"线程1");//传入时传入名称
Thread thread2 = new Thread(test);
thread2.setName("线程2");//启动前改名
线程有默认名称
获取名称:
String 线程名称 = 线程对象.getName();
休眠
作用:线程等待一会
语法:Thread.sleep (休眠时间);
1,休眠时间单位为毫秒 1000毫秒==1秒
2,在那个线程中用就是让那个线程休眠
3,不会释放锁对象
thread睡1s,
try {
thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
合并
作用:将多个线程合并为同一个线程
语法:
线程对象.join();
try {
thread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
将thread执行完后再执行当前代码,相当于把两者合并了
合并前
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 27; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(i);
}
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 97; i < 123; i++) {
try {
thread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println((char)i);
}
}
});
thread.start();
thread2.start();
线程对象.join();
在那个线程调用,就是把 线程对象 名的线程合并过来
礼让
作用:放弃本次抢夺的CUP执行权,重新参与抢夺
语法:Thread.yield();
注意:在那个线程中使用就是让那个线程放弃本次争夺的CPU权
Thread.yield();
放弃本次,下次还会争夺,是个概率问题,有可能这次放弃,下次还是挣到了前面
优先级
作用:增大或减小线程抢夺到CPU执行权的概率
语法: 设置优先级 线程对象.setPriority(优先级);
获取优先级
int 线程优先级 = 线程对象.getPriority();
注意: 1,优先级取值范围1~10,超过范围会报错
2,在线程启动前设置
3,线程的优先级是5
thread1.setPriority(9);//设置权限
thread1.start();
thread2.start();
int a=thread1.getPriority();//获取权限
System.out.println("权限"+a);
守护线程
子线程:
前台线程
守护线程(后台线程)
如果创建一个子线程,默认为前台线程
可以通过: 线程对象.setDaemon(true); 将子线程设置为守护线程
前台线程与守护线程区别:
当一个进程有前台线程存活时,那么该进程就不会被系统回收,直到当前进程中所有前台程序执行完毕
如果一个进程所有前台线程执行完毕,还有守护线程正在执行,那么此时不管守护线程是否执行完毕,进程 都将被销毁
线程的生命周期:
1.初始状态:NEW
线程创键后,到启动前
2.就绪状态:Ready
线程启动后,还没有争夺CPU执行权,准备争夺
3.运行状态:Running
线程争夺到CUP执行权后,执行run中的代码
当CPU执行权限时间到了后
run方法中代码执行完毕进入终止状态
没有执行完,回到就绪状态
4.终止状态:Terminated
当线程执行完run方法中的代码后会进入到该状态,等待被系统回收
5.:Timed Waiting 有限期等待
如使用线程类调用sleep方法,线程会进入到有限期等待
无限期等待 如A线程合并到B线程,A线程就会陷入无限期等