一、创建线程
1)继承Thead类:对于当前线程的引用,可以直接使用this引用
//1.继承Thread,创建线程类
class MyThread extends Thread{
//这里的run方法重写了Thread中的方法
public void run(){
System.out.println(" 线程运行 ");
}
}
public class Main{
public static void main(String[] args){
//2.创建MyThread 类的实例
MyThead t = new MyThread();
//3.调start来启用线程
t.start();
}
}
2)实现Runnable接口:此时的this表示的是对与MyRunnable的引用,当前线程对象要用Thread.currentThread()
class MyRunnable implements Runnable{
public void run(){
System.out.println("线程运行");
}
}
public class Main{
public static void main(String[] args){
Thread t = new Thread(new MyRunnable());
t.start();
}
}
3) 匿名内部类创建Thread子类对象
public class Main{
public static void main(String[] args){
Thread t = new Thread(){
public void run(){
System.out.println("线程运行");
}
};
}
}
4)匿名内部类创建Runnable子类对象
public class Main{
public static void main(String[] args){
Thread t = new Thread(new Runnable(){
public void run(){
System.out.println("线程运行");
}
});
}
}
5)lambda 表达式创建Runnable子类对象
Thread t = new Thread(() -> {
System.out.println("线程运行");
});
二、线程中断
线程中断并不是说让线程立即停止,而是通知线程该停止了,是否真正意义上的停止还看线程中的代码的写法。
线程中断的常见的两种方式:1.通过共享的标记沟通 2.调用interrupt()方法来通知
//通过共享的标记沟通 对于flag值的改变来通知线程的中断
public class ThreadDemo{
public static boolean flag = false;
public static void main(String[] args){
Thread t = new Thread(() -> {
while(flag){
System.out.println("hello thread");
try{
Thread.sleep(1000);
}catch(InterruptedException e){
e.printStackTrace;
}
}
};
t.start();
// 在主线程里就可以随时通过 flag 变量的取值来操作 t 线程是否结束.
flag = false;
}
}
public class ThreadDemo{
public static void main(String[] args) throws InterruptedExcetion{
Thread t = new Thread(() -> {
while(!Thread.currentThread().isInterrupted()){
System.out.println("hello Thread");
try{
Thread.sleep(1000);
}catch(InterruptedException e){
e.printStackTrace();
//当这里的线程没有主动break时,线程在抛出异常后会继续运行循环
}
}
});
t.start();
Thread.sleep(3000);
t.interrupt();
}
}
若是线程在sleep中休眠,此时调用interrupt会把线程唤醒,从而会触发sleep中的异常,提前将线程返回。
此时interrupt相当于做了两件事情:
一是把线程内部的标志位(boolean)给设置成true
二是若线程处于sleep,触发异常,把sleep唤醒,同时还会把刚刚设置成true的标志位设置回false
以上两点形成的运行结果如下:
调用interrupt只是通知线程该终止,是否要真的终止,还得看线程内的代码
public class ThreadDemo{
public static void main(String[] args) throws InterruptedExcetion{
Thread t = new Thread(() -> {
while(!Thread.currentThread().isInterrupted()){
System.out.println("hello Thread");
try{
Thread.sleep(1000);
}catch(InterruptedException e){
e.printStackTrace();
break; //线程响应请求,立刻终止
}
}
});
t.start();
Thread.sleep(3000);
t.interrupt();
}
}
运行结果如下:
public class Main{
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
System.out.println("hello thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
//稍后进行终止,以下可加入其他代码,以便在终止前有其他任务请求
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
break;
}
}
});
t.start();
Thread.sleep(3000);
t.interrupt();
}
三、线程等待
线程调度是抢占式执行,是一个随机调度的过程,但往往随机是不可靠的,有的时候就需要等待一个线程完成他的工作后才能进行下一步工作,此时就需要线程等待join(),来控制两个线程之间的结束顺序。
public class ThreadDemo{
public static void main(String[] args){
Thread t = new Thread(() -> {
System.out.println("hello Thread");
try{
Thread.sleep(1000);
}catch(InterruptedException e){
e.printStackTrace();
}
});
t.start;
try{
Thread.sleep(5000);
}catch(InterruptedExcetion e){
e.printStackTrace();
}
System.out.println("join之前");
try{
t.join();
}catch(InterruptedExcetion e){
e.printStackTrace();
}
System.out.println("join之后");
}
}
注:当线程执行到join的时候就会阻塞,进入阻塞队列,知道Thread线程执行结束,主线程main才会进入就绪队列,才可以被操作系统内核调度
四、线程休眠
线程休眠会由就绪队列进入阻塞队列。当指定的休眠时间结束,线程就可以由阻塞到就绪队列中,从而能够被调度,实际的休眠时间会大于等于我们设定的时间,以毫秒为单位,方法为sleep().