目录
1.创建线程
1.2:run()和start()方法
1.3:Thread的几个常见属性
2.线程的有关操作
2.1:启动一个线程:start()
2.2:中断一个线程
2.2.1:使用自定义的变量来作为标志位
2.2.2:使用Thread.interrupted()代替自定义标志位
2.2.3:标志位不会被清除 Thread.currentThread().isInterrupted()
2.3:等待一个线程 join()
2.4:获取当前线程引用 currentThread()
2.5:休眠当前线程 slepp()
前言:
在前一篇我们了解了何为线程和进程,并大致的知道线程和进程之间的区别和联系,今天我们进一步的来了解线程,该怎么创建一个线程。
1.创建线程
class MyThread extends Thread{
@Override
public void run() {
System.out.println("这里是继承Thread来创建一个线程类");
}
}
//实现Runnable接口来创建线程
class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println("实现Runnable接口来创建一个线程类");
}
}
public class ThreadDemo1 {
public static void main(String[] args) {
//继承Thread来创建一个线程类
MyThread thread=new MyThread();
thread.start();
//这里就是描述一个任务
MyRunnable runnable=new MyRunnable();
//把任务交给一个线程来完成。
Thread thread1=new Thread(runnable);
thread1.start();
//利用lambda来创建一个线程
Thread thread2=new Thread(()->{
System.out.println("这是lambda来创建一个线程。");
});
thread2.start();
}
}
看代码,里面有很多run(),start()方法,为啥有这些呢?接下来我们来进一步了解run()方法,start()方法
1.2:run()和start()方法
1. start()是真正的操作系统中创建一个新的线程。是真正的实现了多线程。
2. start()方法启动线程后自动调用run()方法。
3. run()方法只是描述了线程要干的活是啥,如果在main中调用run()方法,此时run()只是Thread类的一个普通的方法。并不会创建一个新的线程。
4. run()方法执行完毕后,start()创建的这个新线程会立马销毁,Thread对象但依旧存在(对象的生命周期和系统内核的线程并非完全一致)。
1.3:Thread的几个常见属性
1.ID getId():
ID是线程的唯一标识,不同线程不会重复。
2.名称 getName():
3.是否后台线程:isDaemon():
后台线程又叫做守护线程,main默认是前台线程,JVM自带的线程都是后台线程。JVM会在一个进程的所有非后台线程结束后,才会结束运行。前台线程会阻止进程结束,前台线程的工作没做完,进程是结束不了的。
4.是否存活:isAlive():
这个是判断内核里面的PCB是否在干活,是在判断当前系统里面的这个线程是不是真的存在。也可以简单的理解,run()方法是否允许结束了。
2.线程的有关操作
2.1:启动一个线程:start()
前面已经讲述了,这里就不在讲述呢
2.2:中断一个线程
这里的中断,并不是让一个线程立即停止下来,而是通知线程,你该停下来了,但至于这个线程会不会停下来,是取决线程自己的(线程内部的代码)。
2.2.1:使用自定义的变量来作为标志位
public class ThreadDemo2 {
private static boolean flag=false;
public static void main(String[] args) throws InterruptedException {
Thread t1=new Thread(()->{
while(!flag){
System.out.println("没被发现,可以继续潜伏");
}
System.out.println("快撤!!");
});
t1.start();
Thread.sleep(1);
flag=true;
}
}
2.2.2:使用Thread.interrupted()代替自定义标志位
为true:就是被终止了
public static void main(String[] args) throws InterruptedException {
Thread t1=new Thread(()->{
while(!Thread.currentThread().isInterrupted()){
System.out.println("她不在,可以继续布置");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("她来了,快撤");
});
t1.start();
Thread.sleep(1);
t1.interrupt();//这个就是将t1这个线程中断
}
}
这里Thread.currentThread():是可以获取当前的线程。
使用Thread.isInterrupted():是会把sleep()方法提前唤醒。
public static void main(String[] args) throws InterruptedException {
System.out.println("原本的中断标志位为:"+Thread.interrupted());
//这里打印出来Thread.interrupted()是false;
Thread t1=new Thread(()->{
for (int i = 0; i <3; i++) {
System.out.println("现在的中断标志位为"+Thread.interrupted());
}
});
t1.start();
t1.interrupt();//这里是将中断标志位设置为true;
}
Thread.isInterrupted() 判断当前线程的中断标志被设置后,会清除自己设置的中断标志,使中断标志恢复原来。就像弹簧一样,按下去,就自己恢复到原来的长度。
2.2.3:标志位不会被清除 Thread.currentThread().isInterrupted()
public static void main(String[] args) throws InterruptedException {
System.out.println("原本的中断标志位为:"+Thread.interrupted());
//这里打印出来Thread.interrupted()是false;
Thread t1=new Thread(()->{
for (int i = 0; i <3; i++) {
System.out.println("现在的中断标志位为"+Thread.currentThread().isInterrupted());
}
});
t1.start();
t1.interrupt();//这里是将中断标志位设置为true;
}
Thread.currentThread().isInterrupted(): 判断指定线程的中断标志被设置,不会清除设置的中断标志位。就像闹钟响了,你把闹钟暂停了,但过一会儿还是回响。
2.3:等待一个线程 join()
线程是一个随机调度的过程,而等待一个线程就是控制线程的结束顺序。
join() 等待t1线程结束,t1线程不结束,main线程就进入阻塞状态.如果在执行join()之前,t 已经结束了,main这个线程就不会阻塞,直接往下走。
这里为啥不一样呢?
join(参数)这里是毫秒,意思就是我最多等待多久,你来晚了,我就走了。这里只看你设置的参数是多久。但是在我设置等待的时间内t1线程已经结束了,main线程也不会继续处于阻塞状态,也会立马运行下去。
2.4:获取当前线程引用 currentThread()
public static void main(String[] args) {
Thread thread=Thread.currentThread();//获取当前线程
System.out.println(thread.getName());
}
在哪个线程中调用,就可以获取到当前线程的实例。getName()获取到线程的名字。
如上代码,的结果就是main。
2.5:休眠当前线程 slepp()
休眠当前线程就用Sleep(),它的举例已经在上面使用过了。这里就不在举例了。
总结:
以上就是我总结的线程的知识点,若有错的,或是不太准确的,请各位铁子留言指错,若感觉不错,请一键三连。