线程创建
(1)继承thread类,重写run方法
class MyThread extends Thread{
@Override
public void run() {
while (true) {
System.out.println("hello thread");
}
}
}//创建一个线程,打印"hello thread"
(2)实现Runnable接口,重写run方法
class runnable implements Runnable{
@Override
public void run() {
while (true){
System.out.println("hello thread");
}
}
}
(3)继承thread,重写run,使用匿名内部类
public class Test {
public static void main(String[] args) {
Thread t=new Thread(){
@Override
public void run() {
while (true){
System.out.println("hello thread");
}
}
};
t.start();
while (true){
System.out.println("hello main");//主线程打印"hello main"
}
}
}
(4)实现Runnable,重写run,使用匿名内部类
public class Test {
public static void main(String[] args) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
while (true){
System.out.println("hello thread");
}
}
});
t.start();
while (true){
System.out.println("hello main");
}
}
}
(5)使用lambda表达式(最常用)
public class Test {
public static void main(String[] args) {
Thread t=new Thread(()->{
while (true){
System.out.println("hello thread");
}
});
t.start();
while (true){
System.out.println("hello main");
}
}
}
线程中断
在java中,想要销毁或终止一个线程,就是让run方法尽快执行完毕。
1 通过手动添加一个标志位来作为run执行结束的条件。
public class test {
private static boolean isQuit=false;//定义一个成员变量
public static void main(String[] args) {
Thread t=new Thread(()->{
while (!isQuit){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("线程工作中");
}
System.out.println("线程工作完毕");
});
t.start();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
isQuit=true;
System.out.println("设置isQuit为true");
}
}
需要注意isQuit是作为类的成员变量,不能写在main里面(变成了局部变量),涉及到lambda的变量捕获规则。
结果
上述代码手动设置了一个成员变量isQuit为标志位,一开始isQuit为false,while里面的循环条件成立,所以子线程会持续打印” 线程工作中“,当主线程休眠时间结束,并且把isQuit设置为true,子线程循环条件不成立,线程结束工作。
上述方法需手动创建标志位,稍微麻烦了一点,并且可以看到当子线程在sleep时主线程修改isQuit,线程并不能及时响应(可以看到运行结果:在修改变量之后,子线程还是执行了一次打印)
有另一种方法可以完成线程的中断。通过thread内部的标志位
public class test {
public static void main(String[] args) {
Thread t=new Thread(()->{
while (!Thread.currentThread().isInterrupted()) {//Thread.currentThread是当前实例,
// 相当于实例化一个t.
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程工作中");
}
});
t.start();
try {
Thread.sleep(5000);
}catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println("让线程终止");
t.interrupt();
}
}
运行结果
可以看到,中断后线程确实抛出异常了,但是并没有停止。这样的机制是java期望当线程收到中断信号时,能自由决定怎么处理,让我们有更多的可操作空间,前提这个可操作空间是通过抛出异常唤醒的(如果没有sleep,就没有这个操作空间了)。
接下来线程可以
1继续执行,假装什么也没听见。
2加上一个break,让线程结束。
3放一些其他工作代码,等完成后在结束。
public class test {
public static void main(String[] args) {
Thread t=new Thread(()->{
while (!Thread.currentThread().isInterrupted()) {//Thread.currentThread是当前实例,
// 相当于实例化一个t.
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
//1假装什么也没听见,继续执行
e.printStackTrace();
break;//2设置break让线程结束
//3做一些其他工作,等完成后再结束
}
System.out.println("线程工作中");
}
});
t.start();
try {
Thread.sleep(5000);
}catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println("让线程终止");
t.interrupt();
}
}
运行结果
可以看到在添加break后,线程确实结束了。
线程等待
一个线程等待另一个线程结束,本质上就是控制线程执行顺序。通过join方法完成。
public class test {
public static void main(String[] args) throws InterruptedException{
Thread t=new Thread(()->{
for (int i = 0; i < 5; i++) {
System.out.println(i);
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
t.start();
System.out.println("等待开始");
// 让主线程来等待 t 线程执行结束.
// 一旦调用 join, 主线程就会触发阻塞. 此时 t 线程就可以趁机完成后续的工作.
// 一直阻塞到 t 执行完毕了, join 才会解除阻塞, 才能继续执行
t.join();
System.out.println("等待结束");
}
}
运行结果
当然也可以调用带有时间参数的join方法设置等待最长时间。
线程休眠
调用sleep()方法,要注意的是sleep是存在精度误差的,不是说时间一到立马执行,因为系统的调度也要花费一定的时间。
public class test {
public static void main(String[] args) throws InterruptedException {
long beg=System.currentTimeMillis();
Thread.sleep(1000);
long end=System.currentTimeMillis();
System.out.println(end-beg);
}
}
执行结果