目录~~~
1.线程创建
2.线程中断
3.线程等待
4.线程休眠
5.获取线程实例
线程创建
线程创建的方式有很多种,接下来介绍5种常见的线程创建方式
1.实现Thread子类,重写run方法
//实现Thread子类来创建线程(继承Thread)
class MyThread extends Thread{
@Override
public void run() {
while (true){
System.out.println("hello world");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
public class Demo1 {
public static void main(String[] args) throws InterruptedException {
MyThread t = new MyThread();
t.start();//当start开始调用,才算创建了线程
while (true){
System.out.println("hello main");
Thread.sleep(1000);
}
}
}
2.实现Runnable接口,重写run方法
//实现Runnable接口来创建线程
class MyRunnable implements Runnable{
@Override
public void run() {
while(true){
System.out.println("hello hi");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
public class Demo2 {
public static void main(String[] args) throws InterruptedException {
MyRunnable runnable = new MyRunnable();
Thread t = new Thread(runnable);//使用这个方法创建线程可以将线程与线程工作本身分开
t.start();
while (true){
System.out.println("hello main");
Thread.sleep(1000);
}
}
}
3.用匿名内部类来实现Thread子类
//使用匿名内部类来实现Thread子类来创建线程
public class Demo3 {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(){
@Override
public void run() {
while (true){
System.out.println("hello hahaha");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
};
t.start();
while (true){
System.out.println("hello main");
Thread.sleep(1000);
}
}
}
4.用匿名内部类来实现Runnable接口
//使用匿名内部类实现Runnable接口来创建线程
public class Demo4 {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(new Runnable(){
@Override
public void run() {
while (true){
System.out.println("+++++++++++++++++");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
});
t.start();
while (true){
System.out.println("*********************");
Thread.sleep(1000);
}
}
}
5.lambda表达式(推荐写法)
//lambda表达式
public class Demo5 {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
while (true){
System.out.println("hello bbb");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
t.start();
while (true){
System.out.println("**************");
Thread.sleep(1000);
}
}
注:
1.run方法里的代码是程序员给线程安排任务
2.要想真正创建线程,不要忘了start方法的调用,只有start调用了,线程才会真正被创建并且运行
线程中断
有时候我们在写代码的时候,会有一些不那么重要的数据运行计算,当我们不想浪费时间等待的时候,我们可以将线程“中断”,这里的中断并不是说在线程运行是直接打断程序,而是加速线程的运行,使线程尽快结束,即让run尽快结束~
(不是打断正在运行的线程,而是到时间线程自己停下)
原理就是在程序中设置一个标志位,当运行到标志位设置的时间时,线程结束
我们有两种手段来实现线程中断
1.自己定义标志位
public class Demo3 {
public static boolean isQuit = true;
public static void main(String[] args) {
Thread t = new Thread(() -> {
while (isQuit){
System.out.println("hello Thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("线程t结束了");
});
t.start();
//让主线程3秒后改变isQuit
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
isQuit = false;
System.out.println("让线程t结束");
}
}
自己定义了一个isQuit标志位,开始为标志位为true,while可以循环打印,在main主线程中设置了3秒后isQuit为false,则线程t在3秒后执行结束
2.使用标准库中自带的标志位
Thread.currentThread().isInterrupted()
currentThread()这是Thread类的静态方法,通过这个方法就可以拿到当前线程的实例(拿到当前线程对应的Thread对象)
isInterrupted()这个方法在判断标志位为true还是为false
简单来说就是在判定此时这个线程是在运行还是已经结束,正在运行为true,结束为false,因此用来作为while循环的判定标志,从而使循环结束
public class Demo4 {
public static void main(String[] args) {
Thread t = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()){
System.out.println("hello Thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
//throw new RuntimeException(e);
break;
}
}
System.out.println("线程t结束了");
});
t.start();
//让主线程3秒后改变isQuit
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
t.interrupt();
System.out.println("让线程t结束");
}
}
而interrupt方法调用后会出现两种结果
1.线程如果在运行,则会设置标志位为true
2.线程如果处于阻塞状态,则设置成true的标志位会被清除,然后循环并并不会被终止,线程继续运行
线程等待
这里介绍一下前台线程与后台线程,一个进程里有多个前台进程和多个后台进程,他们并发执行,当前台进程全部结束后,无论后台线程是否还在工作,都会被停止,进程结束,反过来,如果后台线程全部结束,而还剩哪怕一个前台线程在运行中,进程也不会结束,也会等到最后一个前台进程结束后进程才会结束,
简单来说就是,进程跟着前台进程走,前台结束,进程结束,不管后台此时怎么样
那么问题来了,由于线程会抢占式执行,当线程们就绪时,由系统内核来决定哪个线程先执行,这是不确定的,所以有时候会出现假如两个线程针对同一个变量进行操作,其中一个线程还没计算完自己的工作,另外一个线程就开始把一个不完整的结果来计算,势必会导致结果出问题,
所以两个线程,我们先让线程1做好自己的工作,另外一个线程2等待线程1结束后才继续执行
综上所述,我们用join方法来实现线程的等待,谁调用了join,谁就先执行,执行完毕后,不调用join的线程才继续执行
比如我想用线程t实现5次打印后,main线程才开始运行,如果不调用join等待线程t先打印完,由于线程并发执行,main会同时运行,t还没结束,main就先结束了
public class Demo7 {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
for (int i = 0; i < 5; i++){
System.out.println("hello Thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
thread.start();
System.out.println("main线程结束了");
}
}
调用join
则main会阻塞等待,直到t结束后,main才结束
线程休眠
这玩意很简单,就是Thread中的sleep方法,以毫秒级来运行程序,比如你想循环打印并且每隔1秒打印一次,则可以调用sleep,调用sleep会出现受查异常,手动try就行了
获取线程实例
在上文标志位那里第二个使用标准库的标志位中的while循环里的判断
Thread.currentThread()
调用这个静态方法可以获取当前线程实例
以下是获取线程的属性
public class Demo2 {
public static void main(String[] args) {
Thread t = new Thread(() -> {
while (true){
System.out.println("hello thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
},"自定义线程");
t.start();
System.out.println(t.getId());//获取线程ID
System.out.println(t.getName());//名字
System.out.println(t.getPriority());//优先级
System.out.println(t.getState());//状态
System.out.println(t.isDaemon());//是否后台
System.out.println(t.isAlive());//是否存活
System.out.println(t.isInterrupted());//是否被打断
}
}