方法一:用一个类 继承Thread 重写run方法
//创建一个类 继承Thread
class MyThread extends Thread {
//run方法是线程的入口
@Override
public void run() {
while (true){
System.out.println("hello Thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
这样一个线程就创建好了,然后可以创建MyThread实例。
public class demo1 {
public static void main(String[] args) throws InterruptedException {
Thread thread = new MyThread();//向上转型 也可以写成MyThread myThread = new MyThread();
//运行线程
thread.start();
while (true){
System.out.println("hello main");
//每1000毫秒打印一次 也就是休眠一秒
Thread.sleep(1000);
}
}
}
方法二:实现 Runnable 接口 重写run方法
class MyRunnable implements Runnable {
@Override
public void run() {
while (true){
System.out.println("hello Runnable");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
我们可以通过实现Runnable接口来实现创建线程
public class demo2 {
public static void main(String[] args) throws InterruptedException {
//runnable表示的是一个可运行的任务 这个任务是交给线程来负责执行的
Runnable runnable = new MyRunnable();
Thread t = new Thread(runnable);
t.start();
while (true){
System.out.println("jello main");
Thread.sleep(1000);
}
}
}
方法三:使用匿名内部类,继承Thread 重写run方法
public class demo3 {
public static void main(String[] args) throws InterruptedException {
//使用匿名类创建 Thread 子类对象
Thread t = new Thread(){
@Override
public void run() {
while (true){
System.out.println("thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
};
t.start();
while (true){
System.out.println("main");
Thread.sleep(1000);
}
}
}
方法四:使用匿名内部类,实现Runnable 重写run方法
public class demo4 {
public static void main(String[] args) {
//使用匿名内部类创建 Runnable 子类对象
Thread t = new Thread(new Runnable() {
@Override
public void run() {
while (true){
System.out.println("thread");
}
}
});
t.start();
while (true){
System.out.println("main");
}
}
}
方法五:使用 lambda 表达式创建 Runnable 子类对象
public class demo5 {
public static void main(String[] args) {
//lambda 表达式创建 Runnable 子类对象
//lambda 表达式本质上是一个匿名函数
Thread t = new Thread(()->{
while (true){
System.out.println("thread");
}
});
t.setDaemon(true);
t.start();
}
}
Thread 类是 JVM 用来管理线程的一个类,换句话说,每个线程都有一个唯一的 Thread 对象与之关联。
创建好线程之后我们可以运行程序观察线程,多线程运行的时候我们可以使用jdk的bin目录下的 jconsole.exe 来观察该进程里多线程的情况。如果运行 jconsole.exe 什么都不显示,就需要以管理员的方式运行。
Thread类的常见构造方法
方法 | 说明 |
---|---|
Thread() | 创建线程对象 |
Thread(Runnable target) | 使用 Runnable 对象创建线程对象 |
Thread(String name) | 创建线程对象,并命名 |
Thread(Runnable target, String name) | 使用 Runnable 对象创建线程对象,并命名 |
**Thread 的几个常见属性 **
属性 | 获取方法 |
---|---|
ID | getId() |
名称 | getName() |
状态 | getState() |
优先级 | getPriority() |
是否为后台线程 | isDaemon() |
是否存活 | isAlive() |
是否被中断 | isInterrupted() |
在Java里面中断/销毁一个线程其实就是让run尽快执行结束,我们可以在代码中手动创建标志位来作为run的结束条件。
public class demo6 {
private static boolean isQuit = false;//设置标志位
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(()->{
System.out.println("线程正在工作");
while (!isQuit){
System.out.println("thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("线程工作结束");
});
t.start();
Thread.sleep(5000);
isQuit=true;
System.out.println("hello");
}
}
运行结果
上述方法手动创建标志位,当线程内部sleep的时候,,主线程修改变量,新线程不能及时响应,我们就可以使用Thread.currentThread().isInterrupted() 来代替自定义标志位。Thread 内部包含了一个 boolean 类型的变量作为线程是否被中断的标记 。
方法 | 说明 |
---|---|
public void interrupt() | 中断对象关联的线程,如果线程正在阻塞,则以异常方式通知, 否则设置标志位 |
public static boolean interrupted() | 判断当前线程的中断标志位是否设置,调用后清除标志位 |
public boolean isInterrupted() | 判断对象关联的线程的标志位是否设置,调用后不清除标志位 |
public class demo7 {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(()->{
//Thread类内部 有一个标志位 可以用来判断当前的循环是否要结束
//Thread.currentThread()就是获取当前线程
while (!Thread.currentThread().isInterrupted()){
System.out.println("线程正在工作");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
//break; //加了break后会立即中断
//我们可以加一些其他的代码 然后再break 这样我们可以有更多的操作空间
}
}
});
t.start();
Thread.sleep(5000);
System.out.println("通过标志位使t线程终止");
//interrupt可以使sleep内部出现一个异常 从而使线程被提前唤醒 手动创建出的标志位无法达到这个效果
t.interrupt();//把上述标志位设置为true 即使线程内部出现阻塞 也可以被唤醒
}
}
我们观察上面代码的运行结果
虽然异常出现了,sleep被唤醒但是循环没有终止,t 线程任然在继续工作,并没有停止。Java这样设定是因为,当java收到要中断信息的时候,我们希望它可以自由决定接下来怎么处理。
等待一个线程我们使用 join()
public class demo8 {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("线程开始工作");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
System.out.println("线程开始等待");
t.join();//主线程等待 t 线程结束 谁调用join谁是被等的
System.out.println("等待结束");
}
}
一旦调用 join 主线程就会发生阻塞,这样 t 线程就可以完成后面的工作,主线程要一直阻塞到 t 线程执行结束才会解除阻塞。
方法 | 说明 |
---|---|
public void join() | 等待线程结束 |
public void join(long millis) | 等待线程结束,最多等 millis 毫秒 |
public void join(long millis, int nanos) | 等待线程结束,但可以更高精度 最多等 nanos 纳秒 |
方法 | 说明 |
---|---|
public static void sleep(long millis) throws InterruptedException | 休眠当前线程 millis 毫秒 |
public static void sleep(long millis, int nanos) throws InterruptedException | 休眠当前线程 nanos 纳秒 |
public class demo11 {
public static void main(String[] args) throws InterruptedException {
System.out.println(System.currentTimeMillis());
Thread.sleep(3 * 1000);//休眠三秒
System.out.println(System.currentTimeMillis());
}
}