线程及其常见方法总结
线程及其常见方法总结
线程与进程的区别:
进程是系统分配资源的最小单位,线程时系统调度的最小单位 ,一个进程内的线程之间是可以共享资源的。
资源开销:每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小。
包含关系:如果一个进程内有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的;线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程。
内存分配:同一进程的线程共享本进程的地址空间和资源,而进程之间的地址空间和资源是相互独立的
影响关系:一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉。所以多进程要比多线程健壮。
执行过程:每个独立的进程有程序运行的入口、顺序执行序列和程序出口。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制,两者均可并发执行
每个进程至少有一个线程存在,即主线程(系统级别的,C语言的主线程) Java级别的主线程:自己写的入口函数main方法(可以没有这个线程)
静态内部类:
package lesson1;
public class InnerClass {
//静态内部类,和普通类使用没有什么区别,只是需要明确是哪个类的内部类
//在其他包中使用时:InnerClass.A()
public static class A{}
}
1
2
3
4
5
6
7
package ll;
import lesson1.InnerClass;
public class B {
public static void main(String[] args) {
//静态内部类的调用
new InnerClass.A();
}
}
1
2
3
4
5
6
7
8
9
10
******************************************************************************************************************
创建线程的方法:
package lesson1;
public class ThreadLook1 {
static class MyThread extends Thread {
@Override
public void run() {
System.out.println("创建线程方法一:继承Thread类");
}
}
static class MyThread1 implements Runnable{
@Override
public void run() {
System.out.println("创建线程方法二:实现Runnable接口");
}
}
public static void main(String[] args) {
MyThread t = new MyThread();
t.start();
Thread t1 = new Thread(new MyThread1());
t1.start();
}
public static void main1(String[] args) {
//创建线程 方法三
Thread t1 = new Thread() {
@Override
public void run() {
System.out.println("使用匿名类创建Thread子类对象");
}
};
t1.start();
//创建线程 方法四
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("使用匿名类创建Runnable子类对象");
}
});
t2.start();
//创建线程 方法五 使用lambda表达式创建Runnable子类对象
Thread t3 = new Thread(() -> System.out.println("使用匿名类创建Thread子类对象"));
Thread t4 = new Thread(() ->{
System.out.println("使用匿名类创建Thread子类对象");
});
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
******************************************************************************************************************
Thread常见的使用方法
方法 说明
Thread() 创建线程对象
Thread(Runnable target) 使用Runnable对象创建线程对象
Thread(String name) 创建线程对象,并命名
Thread(Runnable target,String name) 使用Runnable对象创建线程对象,并命名
示例:
Thread t1 = new Thread();
Thread t2 = new Thread(new MyThread1());
Thread t3 = new Thread("线程名称");
Thread t4 = new Thread(new MyThread1(),"线程名称");
1
2
3
4
******************************************************************************************************************
Thread常见的属性
属性 获取方法
ID getId()–线程的唯一标识,不会重复
名称 getNmae()
状态 getState()
优先级 getPriority() --优先级高的线程理论上更容易被调度到
是否后台(守护)线程 getDaemon()–JVM会在一个进程的所有非后台线程结束后才会结束运行
是否存活 isAlive()–run方法是否结束
是否被中断 isInterrupted()
示例:
package lesson1;
public class ThreadLook4 {
public static void main(String[] args) {
Thread t = new Thread(new Runnable() { //子线程
@Override
public void run() {
while (true) {
}
}
},"main子线程"); //命名
t.start();
System.out.println(t.getId()); //12
System.out.println(t.getName()); //main子线程
System.out.println(t.getState()); //RUNNABLE
System.out.println(t.getPriority()); //5
System.out.println(t.isDaemon()); //false
System.out.println(t.isAlive()); //true
System.out.println(t.isInterrupted()); //fals
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
运行结果如下:注意此时线程还未结束运行(关于守护线程的测试)
当在t.start()线程启动之前使用t.setDaemon(true)设置守护线程之后再运行程序,程序结束运行。也就是说,对于Java线程,只要有一个非守护线程还没有终止,进程就不会结束。
同时对于Thread.currentThread().getName 和 t.getName() this.getName()三者之间的不同需要注意
总结:
Thread提供静态方法currentThread()来供我们调用,可以避免this无法获取到main线程的问题。
通过继承Thread 创建线程时,可以使用this关键字去调用继承自父类Thread的方法,this就是当前的对象。
Thread.currentThread()可以获取当前线程的引用,一般都是在没有线程对象又需要获得线程信息时通过Thread.currentThread()获取当前代码段所在线程的引用,且通过Runnable接口实现线程创建时,在run()里面只能使用Thread.currentThread()
public static void main(String[] args) {
Thread t = new Thread() {
@Override
public void run() {
System.out.println(this.getName() + " Thread + this + run"); //Thread-0 Thread + this + run
//System.out.println(t.getName()); //编译错误
System.out.println(Thread.currentThread().getName() + " Thread + current + run"); //Thread-0 Thread + current + run
}
};
t.start();
//System.out.println(this.getName); //编译错误
System.out.println(t.getName() + " Thread + t.getName"); //Thread-0 Thread + t.getName
System.out.println(Thread.currentThread().getName() + " Thread + current"); //main Thread + current
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
//System.out.println(this.getName); //编译错误
//System.out.println(t1.getName()); //编译错误
System.out.println(Thread.currentThread().getName() + " Runnable + current + run"); //Thread-1 Runnable + current + run
}
});
t1.start();
//System.out.println(this.getName); //编译错误
System.out.println(t1.getName() + " Runnable + t.getName"); //Thread-1 Runnable + t.getName
System.out.println(Thread.currentThread().getName() + " Runnable + current"); //main Runnable + current
Thread.currentThread().setName("主线程");
System.out.println(Thread.currentThread().getName()); //主线程
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
start() VS run() —区别
基础认识:代码在哪个线程执行,就是由哪个线程执行代码行
start() 会向系统申请启动某个线程,如果该线程处于运行状态,会自动执行run()
run() 通过 Thread 或者 Runnable 类定义要执行的任务代码,即线程再运行态执行的代码 如果不调用start() 而直接调用 run()[线程体] ,相当于Java对象直接调用普通实例方法.
start 启动线程 ,线程处于就绪态,并没有运行,一旦得到cpu时间片,就开始执行run()方法,这时此线程处于运行态,这里方法 run()称为线程体,它包含了要执行的这个线程的内容,run方法运行结束,此线程随即终止。
******************************************************************************************************************
PS:
如何同时启动多个线程?
代码如下:
package lesson1;
public class ThreadLook2 {
public static void main(String[] args) {
//同时启动20个线程 每个线程从 0+1的方式加到99;
for (int i = 0; i < 20;i++) {
Thread t = new Thread(new Runnable() {
@Override
public void run() { //在多线程环境下,即使同一段代码块,也是可以并发并行执行
for (int i = 0; i < 100;i++) {
if (i == 99 ) {
System.out.println(i);
}
}
}
});
t.start();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
注意:某个线程抛run异常 整个线程结束 但是不会影响其他线程
package lesson1;
public class ThreadLook3 {
public static void main(String[] args) {
Thread t = new Thread(new Runnable() { //子线程
@Override
public void run() {
for(int i = 0; i < 10;i++) {
if(i == 6) {
//某个线程抛run异常 整个线程结束 但是不会影响其他线程
//线程中处理异常的方式 线程对象.setUncaughtExceptionHandler()
//或者自己在run()方法里捕获
throw new RuntimeException();
}
System.out.println(i);
}
}
},"main子线程"); //命名
t.start();
while (true) { //main线程
}
//子线程结束 main线程继续
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
运行结果如下:此时虽然run线程结束,但是main线程还没有结束
————————————————
版权声明:本文为CSDN博主「柠七99」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/m0_46657493/article/details/114686894