github: https://github.com/ValjeanShaw
blog: https://valjeanshaw.github.io/
优快云: https://blog.youkuaiyun.com/im_xiao
创建java线程的两种方式和启动
-
继承Thread类
继承Thread类,然后重写run()方法,通过线程的start()开启线程
public class RunByThread extends Thread{ @Override public void run(){ while(true){ try{ Thread.sleep(5000); System.out.println("running by thread......"); }catch (Exception e){ e.printStackTrace(); } } } }
-
实现Runnable接口
与Thread类似,实现Runnable接口,重写其中的run()方法,通过线程的start()开启线程。
public class RunByRunnable implements Runnable { public void run() { while(true){ try{ Thread.sleep(1000); System.out.println("running by runnable......"); }catch (InterruptedException e){ System.out.println("interrupted..."); e.printStackTrace(); }catch (Exception e){ e.printStackTrace(); } } } }
3.启动线程
继承Thread类的子类,可通过[1.创建新对象]或者[2.创建对象放入Thread类]来创建线程
实现Runnable接口的方法,通过新建对象,放入Thread类中来创建线程。因为Runnable接口只有run()方法。
使用Thread提供的start()方法启动线程
public class StartThead { public static void main(String[] args) { //继承Thread类的方法,可以通过以下两种方法开启线程 //1. 创建实例 RunByThread runByThread = new RunByThread(); runByThread.start(); //2. 创建对象,放入Thread中 Thread threadRun = new Thread(new RunByThread()); threadRun.start(); threadRun.isInterrupted(); //实现Runnable接口的方法,通过以下一种方法开启线程。 //创建对象,放入Thread中 Thread thread = new Thread(new RunByRunnable(),"runByThread"); thread.start(); } }
线程的优先级别
现代操作系统基本采⽤时分的形式调度运⾏的线程,操作系统
会分出⼀个个时间⽚,线程会分配到若⼲时间⽚,当线程的时间⽚
⽤完了就会发⽣线程调度,并等待着下次分配。
设置线程的优先级,目的是按照线程优先级给线程分配时间片的多少,优先级越高,时间片越多。
- 优先级范围: 1-10
- 方法 setPriority(int)
代码实例:
public class RunByRunnable implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
public static void main(String[] args) {
RunByRunnable runByRunnable = new RunByRunnable();
Thread thread1 = new Thread(runByRunnable,"run1");
Thread thread2 = new Thread(runByRunnable,"run2");
Thread thread3 = new Thread(runByRunnable,"run3");
Thread thread4 = new Thread(runByRunnable,"run4");
thread1.setPriority(5);
thread2.setPriority(3);
thread3.setPriority(8);
thread4.setPriority(1);
thread1.start();
thread2.start();
thread3.start();
thread4.start();
}
}
(敲黑板!!)在不同的JVM以及操作系统上,线程规划会存在差异,有些操作系统甚⾄会忽略对线程优先级的设定。so: 线程优先级不能作为程序正确性的依赖
线程的状态
java线程中一共有6种状态:
- new 新创建状态,还未调用start()方法
- runnable 运行状态,java中,将就绪和运行统称“运行中”
- blocked 阻塞状态,线程阻塞于锁
- waiting 等待状态,一直等待通知或中断
- time_waiting 超时等待,等待通知或中断,超时后自动返回
- terminated 当前线程已经执行完毕
Daemon线程
Daemon线程即为守护线程,是一种支持性线程,主要用于程序后台中支持性工作。例如垃圾回收。当一个Java虚拟机不存在非Daemon的时候,Java虚拟机会自动退出,不论Daemon是否执行完毕,是什么状态。
方法: thread.setDaemon(true);
以下代码,可测试Daemon的运行是否会被强制杀掉
public class DaemonThread extends Thread {
@Override
public void run() {
try {
System.out.println("DaemonThread running start");
TimeUnit.SECONDS.sleep(1);
System.out.println("DaemonThread running end");
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("DaemonThread InterruptedException");
} catch (Exception e) {
e.printStackTrace();
System.out.println("DaemonThread exception");
} finally {
System.out.println("DaemonThread finally");
}
}
public static void main(String[] args) {
DaemonThread daemonThread = new DaemonThread();
daemonThread.setDaemon(true);
daemonThread.start();
}
}
执行结果:
DaemonThread running start
该程序有两个线程,一个主线程,一个被设置为Daemon的线程。守护线程开始执行后,进入睡眠状态。然后主线程执行完毕,这时JVM发现没有了非守护线程,于是直接退出了。Daemon线程中未执行完的代码,也不会再执行。
线程中断的概念和使用
中断可以理解为线程的一个标识位状态。它表示一个运行中的线程是否被其它线程进行了中断操作。
使用:
A线程对B线程要进行中断: 在A中调用,B.interrupt();
B线程对A线程进行响应:通过调用方法 isInterrupted()方法判断是否被打断,true为中断过,false为未中断过。
标识位复位:Thread.interrupted
当线程为终结状态,即使线程被中断过,标志位也为false
当抛出InterruptedException异常时,jvm会先将中断标志位清除,所以isInterrupted() 为false。
实例代码
public class ThreadInterrupt {
public static void main(String[] args) {
//sleepThread不停的尝试睡眠
Thread sleepThread = new Thread(new SleepRunner(), "sleepThread");
sleepThread.setDaemon(true);
//budyThread线程一直在执行
Thread busyThread = new Thread(new BusyRunner(), "busyThread");
busyThread.setDaemon(true);
sleepThread.start();
busyThread.start();
//休眠几秒钟,让两个线程充分运行
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
sleepThread.interrupt();
busyThread.interrupt();
System.out.println("sleepThread interrupted is " + sleepThread.isInterrupted());
System.out.println("busyThread interrupted is " + busyThread.isInterrupted());
//防止两个线程提前退出
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class SleepRunner implements Runnable {
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class BusyRunner implements Runnable {
@Override
public void run() {
while (true) {
//xxx 爱执行什么执行什么吧
}
}
}
执行结果
sleepThread interrupted is false
busyThread interrupted is true
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at ThreadPackage.SleepRunner.run(ThreadInterrupt.java:57)
at java.lang.Thread.run(Thread.java:748)
抛出InterruptedException的线程,中断位被清除了,另外一个线程,就没有被清除
总结
本篇文章主要讲解Java线程的基础,使用。重点在于Java线程的创建和开启。
全部代码见:
https://github.com/ValjeanShaw/MyConcurrent/tree/develop/src/main/java/ThreadPackage