如果你觉得我的文章有帮助到你,还请【关注➕点赞➕收藏】,得到你们支持就是我最大的动力!!!
⚡版权声明:本文由【马上回来了】原创、在CSDN首发、需要转载请联系博主。
版权声明:本文为CSDN博主「马上回来了」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
新的知识开始喽
线程是操作系统里的概念,操作系统内核实现了这样的机制,并且对用户提供了API供用户使用.
java标准库中Thread可以视为是对操作系统提供的API进行了进一步的抽象和封装.
①自定义子类继承Thread类
class MyThread extends Thread{
@Override
public void run() {
while (true){
System.out.println("hello thread");
try {
Thread.sleep(1_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Demo1 {
public static void main(String[] args) {
MyThread t = new MyThread();
t.start();
while (true){
System.out.println("hello main");
try {
Thread.sleep(1_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
②自定义类实现Runnable接口
class MyRunnable implements Runnable{
@Override
public void run() {
while (true){
System.out.println("hello thread");
try {
Thread.sleep(1_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Demo2 {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread thread1 = new Thread(myRunnable);
thread1.start();
Thread thread2 = new Thread(myRunnable);
thread2.start();
while (true){
System.out.println("hello main");
try {
Thread.sleep(1_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
③创建Thread的匿名内部类
public class Demo3 {
public static void main(String[] args) {
//Thread匿名内部类
Thread thread = new Thread(){
@Override
public void run() {
System.out.println("hello thread");
try {
Thread.sleep(1_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();
while (true){
System.out.println("hello main");
try {
Thread.sleep(1_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
④创建Runnable的匿名内部类
public class Demo4 {
public static void main(String[] args) {
//runnable匿名内部类作为参数传给Thread的构造方法
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("hello thread");
try {
Thread.sleep(1_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
while (true){
System.out.println("hello main");
try {
Thread.sleep(1_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
⑤lambda表达式
public class Demo5 {
public static void main(String[] args) {
//lambda表达式
Thread thread =new Thread(()->{}){
@Override
public void run() {
System.out.println("hello thread");
try {
Thread.sleep(1_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();
while (true){
System.out.println("hello main");
try {
Thread.sleep(1_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
String name是给线程取名字,如果没有给线程取名字,操作系统会自动生成名字.
构造方法里传了String name
public class Demo7 {
public static void main(String[] args) {
Thread thread = new Thread(()->{
while (true){
System.out.println("hello thread");
try {
Thread.sleep(1_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"这是我的多线程");
thread.start();
System.out.println("main线程执行结束");
}
}
public class Demo7 {
public static void main(String[] args) {
Thread thread = new Thread(()->{
while (true){
System.out.println("hello thread");
try {
Thread.sleep(1_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
//将thread进程设置为后台进程
//必须在start启动前设置,调用start之后就无法在设置为后台进程
//thread.setDaemon(true);//main进程结束后,thread是后台进程,所以thread进程会自动结束
thread.start();
System.out.println("main线程执行结束");//这里线程默认是前台进程,即使是main线程结束,thread进程默认是前台进程,前台进程会阻止进程退出,所以thread进程不会就结束
}
}
是否是存活
是否是后台进程:默认创建的进程是前台进程,前台进程如果执行完了会阻止进程退出,而后台进程执行完了,不会阻止阻止进程退出,main就是前台进程.
如果所有的前台进程都执行完了,及时后台进程没有执行完,进程也会退出.
public class Demo {
public static void main(String[] args) {
Thread thread = new Thread(()->{
while(true){
System.out.println("hello thread");
try {
Thread.sleep(1_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"这是俺的线程");
thread.start();
System.out.println(thread.getId());//12
System.out.println(thread.getName());//这是俺的线程
System.out.println(thread.getPriority());//5
System.out.println(thread.isDaemon());//false
System.out.println(thread.getState());//TIMED_WAITING
System.out.println(thread.isAlive());//true
System.out.println(thread.isInterrupted());//false
}
}
当Thread创建好了一个线程对象时,并且重写了run方法时,线程并没有开始执行,也就是操作系统底层还没有创建出一个正真的线程,只有当调用start方法后,操作系统底层才会正真的创建出一个线程(PCB)并且执行这个线程.
这里要注意run方法与start方法的区别:
run方法只是去安排线程要执行的任务,并没有创建线程;
start方法则是在操作系统内核里创建出了一个线程(PCB)
这篇文章线程中断里详细的讲解了线程中断的几种方式。
线程之间的调度顺序是不确定的,可以通过一些特殊操作来对调度的顺序进行干预,其中join方法就可以控制线程之间执行的顺序。
看下面代码:
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(){
@Override
public void run() {
System.out.println("t线程开始" );
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
System.out.println("t线程结束");
}
};
t.start();
t.join();
System.out.println("main线程开始");
System.out.println("main线程结束");
}
运行结果:
注意如果t线程在join之前就已经结束了,那么main线程就不会在阻塞等待了。
join还有时间参数的重载方法:
Thread里提供了sleep方法,这个方法可以使线程休眠一会儿,也就是使线程阻塞一会儿
public static void main(String[] args) {
Thread t = new Thread(){
@Override
public void run() {
System.out.println("t线程开始休眠1s");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t线程休眠结束");
}
};
t.start();
}
运行结果:
那么问题来了,如果sleep参数是1s,那么线程真的是只休眠一秒吗?
不一定!!!
一般会多余1s,多多少具体看操作系统调度的时间开销,可能快(<1ms)也可能慢(>10s),而对于一般的操作系统的调度时间开销是不可预期的,有时候快,有时候慢。
在操作系统里已经对pcb已经有了一个状态的描述,java里觉得这个描述不太合适,所以又自己弄了一套状态规则:
今天的你看懂这里又学到了很多东西吧
下次见喽