目录
线程创建
线程创建
1.继承Thread类,重写run
//继承Thread,创建线程类
class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 3; i++) {
try {
System.out.println("hello Thread");
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
public class D1 {
public static void main(String[] args) throws InterruptedException {
//创建MyThread类的实例
MyThread thread = new MyThread();
//调用start方法创建线程
thread.start();
for (int i = 0; i < 3; i++) {
System.out.println("hello main");
Thread.sleep(1000);
}
}
}
2.实现Runnable接口,重写run
//实现Runnable接口
class MyRunnable implements Runnable{
@Override
public void run() {
//描述了线程要完成的逻辑
for (int i = 0; i < 3; i++) {
System.out.println("hello Thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
public class D2 {
public static void main(String[] args) throws InterruptedException {
MyRunnable runnable = new MyRunnable();
//线程要执行的任务通过Runnable描述
Thread t = new Thread(runnable);
t.start();
for (int i = 0; i < 3; i++) {
System.out.println("hello main");
Thread.sleep(1000);
}
}
}
3.匿名内部类创建Thread子类对象
public class D3 {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(){
@Override
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println("hello Thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
};
t.start();
//主线程
for (int i = 0; i < 3; i++) {
System.out.println("hello main");
Thread.sleep(1000);
}
}
}
4.匿名内部类创建Runnable子类对象
public class D4 {
public static void main(String[] args) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println("hello thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
});
t.start();
//主线程
System.out.println("hello main");
}
}
5.lambda表达式创建Runnable子类对象
public class D5 {
public static void main(String[] args) {
Thread t = new Thread(()->{
for (int i = 0; i < 3; i++) {
System.out.println("hello Threaad");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
t.start();
System.out.println("hello main");
}
}
Thread常见属性
属性 | 获取方法 |
---|---|
ID | getId() |
名称 | getName() |
状态 | getState() |
优先级 | getPriority |
是否后台线程 | isDaemon() |
是否存活 |
isAlive() |
是否被中断 | isInterrupted |
后台线程:线程在执行过程中,不能阻止进程结束。
前台线程:线程在执行过程中,能够阻止进程结束。
start和run
start方法:
- start方法的作用是真正的去申请系统线程,分配线程资源
- 调用start方法后, start方法内部会调用Java 本地方法(封装了对系统底层的调用)真正的启动线程,并执行run方法中的代码,run 方法执行完成后线程进入销毁阶段。
一个Thread对象只能调用一次start。
run方法:
- run方法的作用是描述线程具体要执行的任务;
- run方法是一个类中的普通方法,主动调用和调用普通方法一样,会顺序执行一次;
线程中断
Java中断一个线程,往往是用一个比较 “温柔的” 方式。通过中断,一个线程可以通知另一个线程,告知它需要停止执行当前任务。
例如,有两个线程A和B,B正在运行,A想要B结束,核心就是A想办法让B的 run方法 执行完毕,此时B自己决定是立即结束还是稍后结束。
在Java中,线程中断是通过调用线程的interrupt()
方法来实现的。
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(()->{
//先获取到线程的引用
Thread currentThread = Thread.currentThread();
while ((!currentThread.isInterrupted())){
System.out.println("hello thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
//throw new RuntimeException(e);
System.out.println("执行catch操作");
break;
}
}
});
t.start();
Thread.sleep(3000);
//在主线程中控制t线程被终止 设置上述标志位
t.interrupt();
}
currentThread()是Thread类的静态方法,用于获取当前正在执行的线程对象。
interrupt()是Thread类里的一个boolean类型的成员,初始状态是 false ,表示未被终止。
一旦外面的线程调用这个方法,就会被设置标志位。
上述代码中,主线程在调用interrupt方法时,由于判定操作和打印操作执行速度非常快,此时大概率 t 线程正在sleep状态,而interrupt方法不仅能够设置标志位,还能将正在sleep的线程唤醒,此时触发了InterruptedException异常,并被catch住,但是,当sleep等阻塞的函数(wait/join)被唤醒后,会清空刚刚interrupt方法设置的标志位,此时如果catch 中没有break/return,那么循环就不会结束。
此时,如果 t 线程想忽视主线程,catch中可以什么都不做,如果想立即结束,就可以在catch中加上break/return来结束线程,如果要想稍后结束,就可以在catch中写上一些其他逻辑,最后再beak/return
线程等待(join)
操作系统对于多线程的执行是“随机调度,抢占式执行的”,线程等待,就是在确定线程的结束顺序,让后结束的线程等待先结束的线程,此时后结束的线程就会进入阻塞状态,一直到先结束的线程结束,阻塞才会解除。
例如,现在有两个线程 A 和 B,在A线程中调用 B.join,意思就是让 A 线程先等待 B 线程结束,A再继续执行。
public static void main(String[] args) throws InterruptedException {
//主线程里创建t线程
Thread t = new Thread(()->{
for (int i = 0; i < 3; i++) {
System.out.println("线程t");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("t结束");
});
t.start();
Thread.sleep(4000);
System.out.println("main等待");
t.join();
System.out.println("main结束等待");
}
上述使用 join() 方法,是无参数的,也就意味着,只要被等待的线程不执行完,等待的线程就会一直阻塞。
方法 | 说明 |
---|---|
public void join() | 等待线程结束 |
public void join(long millis) | 等待线程结束,最多等millis毫秒 |
public void join(long millis,int nanos) | 同上,但能更高精度 |
线程休眠
使用Threaad.sleep()方法可以使线程休眠
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
线程执行sleep,就会使这个线程不参与 cpu调度,从而把 cpu 资源让出来,给别人使用,这样的操作称为 “放权”,即放弃使用cpu的权利
线程状态
1.NEW
当前虽然有Thread对象,但是内核的线程还没有(还没调用start)
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(()->{
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
System.out.println(t.getState());
t.start();
}
2.TERMINATED
当前Thread对象虽然还在,但是内核的线程已经销毁(线程已经结束了)
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(()->{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
t.start();
System.out.println(t.getState());
}
3.RUNNABLE
就绪状态,正在cpu上运行 / 随时可以去cpu上运行
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(()->{
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
t.start();
System.out.println(t.getState());
}
4.BLOCKED
因为锁竞争而引起的阻塞
5.TIMED_WAITING
有超时间的等待,比如sleep,或者join带参数版本
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(()->{
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
t.start();
Thread.sleep(500);
System.out.println(t.getState());
}
6.waiting
没有超时间的阻塞等待
public static void main(String[] args) throws InterruptedException {
Thread mainT = Thread.currentThread();
Thread t = new Thread(()->{
while(true){
try {
System.out.println(mainT.getState());
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
t.start();
//由于t线程是持续while,因此join不会返回
//观察主线程状态就能看到waiting
t.join();
}
上述线程状态,可通过 jconsole 观察。