目录
1.1 实现 Runnable 接口,重写 run 方法,无返回值
1.2 实现 Callable 接口,重新 call 方法,有返回值
1.3 继承 Thread 类,重写 run 方法,无返回值
每一段代码,都是可以单独执行的,可以放到本地,查看一下执行效果。
千篇一律的看,不如自己动手实践一下,让咱们靠着理解,去加深记忆。
1. 线程的实现方式
线程的的实现方式分为三种。
1.1 实现 Runnable 接口,重写 run 方法,无返回值
1.2 实现 Callable 接口,重新 call 方法,有返回值
1.3 继承 Thread 类,重写 run 方法,无返回值
前两种是创建了一个可执行任务,直接调用 run 方法、call 方法,并不是以多线程的方式进行执行的。只有通过 Thread 类的 star 方法,启动的,才是以多线程的方式进行执行的。
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
public class ThreadTest {
public static void main(String[] args) throws Exception {
long start = System.currentTimeMillis();
System.out.println("主线程 开始");
System.out.println("1. Runnable 测试代码");
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("Runnable " + Thread.currentThread().getName() + ":runing...");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Runnable " + Thread.currentThread().getName() + ":over...");
}
};
new Thread(runnable).start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("");
System.out.println("2. Callable 测试代码");
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
System.out.println("Callable " + Thread.currentThread().getName() + ":runing...");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Callable " + Thread.currentThread().getName() + ":返回值,娃哈哈...");
return "娃哈哈";
}
};
FutureTask<String> futureTask = new FutureTask<>(callable);
new Thread(futureTask).start();
System.out.println("callable方式 返回值:" + futureTask.get());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("");
System.out.println("3. 继承 Thread 重写 run 方法");
MyThread myThread = new MyThread();
myThread.start();
System.out.println("主线程 结束,耗时 " + (System.currentTimeMillis() - start));
}
}
class MyThread extends Thread {
@Override
public void run() {
System.out.println("继承 Thread " + Thread.currentThread().getName() + ":runing...");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("继承 Thread " + Thread.currentThread().getName() + ":over...");
}
}
2. 线程的生命周期
线程的生命周期可以整体可以涵盖为 4 种流程,分别是,新建、就绪、阻塞、终止。
这 4 种流程对应了 6 种状态。
新建:new
就绪:runnable
阻塞:blocked、waiting、timed waiting
终止:terminated
2.1 线程状态:new
public class ThreadTest {
public static void main(String[] args) throws Exception {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "线程A");
System.out.println("[ " + thread.getName() + " ] 的状态是:" + thread.getState());
//控制台输出: [ 线程A ] 的状态是:NEW
}
}
2.2 线程状态:runnable
public class ThreadTest {
public static void main(String[] args) throws Exception {
// 1. 声明一个线程
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + " runing... " + i);
}
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "线程A");
// 2. 启动线程
thread.start();
// 3. 查看线程状态 [ 因为CPU执行顺序是不一定的,此时假设,启动后,执行了,主线程中,查看状态的代码 ]
System.out.println("[ " + thread.getName() + " ] 的状态是:" + thread.getState());
// 控制台输出:
// [ 线程A ] 的状态是:RUNNABLE
// 线程A runing... 0
// ......
// 线程A runing... 9
}
}
2.3 线程状态:blocked
import sun.misc.Lock;
public class ThreadTest {
public static void main(String[] args) throws Exception {
// 1. 生命锁对象
Lock lock = new Lock();
// 2. 声明两个线程
MyThread threadA = new MyThread(lock, "线程A");
MyThread threadB = new MyThread(lock, "线程B");
threadA.start();
threadB.start();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 3. 查看状态
System.out.println("[ " + threadA.getName() + " ] 的状态是:" + threadA.getState());
System.out.println("[ " + threadB.getName() + " ] 的状态是:" + threadB.getState());
}
}
class MyThread extends Thread {
private Lock lock = null;
public MyThread(Lock lock, String name) {
this.lock = lock;
super.setName(name);
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ":runing...");
try {
System.out.println(Thread.currentThread().getName() + ":runing...开始争夺锁");
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + ":runing...拿到了锁");
System.out.println(Thread.currentThread().getName() + ":runing...模拟业务执行...");
Thread.sleep(1000);
}
System.out.println(Thread.currentThread().getName() + ":over...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
2.4 线程状态:waiting
import sun.misc.Lock;
public class ThreadTest {
public static void main(String[] args) throws Exception {
// 1. 生命锁对象
Lock lock = new Lock();
// 2. 声明两个线程
MyThread threadA = new MyThread(lock, "线程A");
MyThread threadB = new MyThread(lock, "线程B");
threadA.start();
threadB.start();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 3. 第一次查看状态
System.out.println("[ " + threadA.getName() + " ] 的状态是:" + threadA.getState());
System.out.println("[ " + threadB.getName() + " ] 的状态是:" + threadB.getState());
try {
Thread.sleep(3000);
synchronized (lock) {
lock.notifyAll();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
// 4. 第二次查看状态
System.out.println("[ " + threadA.getName() + " ] 的状态是:" + threadA.getState());
System.out.println("[ " + threadB.getName() + " ] 的状态是:" + threadB.getState());
}
}
class MyThread extends Thread {
private Lock lock = null;
public MyThread(Lock lock, String name) {
this.lock = lock;
super.setName(name);
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ":runing...");
try {
System.out.println(Thread.currentThread().getName() + ":runing...开始争夺锁");
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + ":runing...拿到了锁");
System.out.println(Thread.currentThread().getName() + ":runing...模拟业务执行...");
lock.wait();
System.out.println(Thread.currentThread().getName() + ":runing...模拟业务执行...2");
}
System.out.println(Thread.currentThread().getName() + ":over...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
2.5 线程状态:timed waiting
public class ThreadTest {
public static void main(String[] args) throws Exception {
// 1. 声明线程
MyThread threadA = new MyThread();
threadA.setName("线程A");
threadA.start();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 2. 查看状态
System.out.println("[ " + threadA.getName() + " ] 的状态是:" + threadA.getState());
// 控制台输出
// 线程A:runing...
// [ 线程A ] 的状态是:TIMED_WAITING
// 线程A:over...
}
}
class MyThread extends Thread {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ":runing...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":over...");
}
}
2.6 线程状态:terminated
public class ThreadTest {
public static void main(String[] args) throws Exception {
// 1. 声明两个线程
MyThread threadA = new MyThread();
threadA.start();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 3. 第一次查看状态
System.out.println("[ " + threadA.getName() + " ] 的状态是:" + threadA.getState());
}
}
class MyThread extends Thread {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ":runing...");
System.out.println(Thread.currentThread().getName() + ":runing...开始争夺锁");
System.out.println(Thread.currentThread().getName() + ":runing...拿到了锁");
System.out.println(Thread.currentThread().getName() + ":runing...模拟业务执行...");
System.out.println(Thread.currentThread().getName() + ":runing...模拟业务执行...2");
System.out.println(Thread.currentThread().getName() + ":over...");
}
}
3. 总结
线程的生命周期分为四种, 新建、就绪、阻塞、终止,对应六种状态,
新建:new,
就绪:runnable,
阻塞:blocked、waiting、timed waiting,
终止:terminated。
当线程被创建出来以后,对应的是new,随后通过start()方法启动对应runnable,cpu切片时间执行完成,但是业务没有走完,线程回归到runable状态,当在cpu切片时间内执行完毕,线程进入terminated 终止状态,线程生命周期结束。
在线程执行过程中,调用sleep、wait 传入时间,随后线程进入阻塞状态中的 timed waiting 定时等待状态,待指定时间过后,线程进入runnable 就绪状态,等待cpu调用。
在线程执行过程中,调用 wait 方法,不传入时间、线程进入到 waiting 等地状态,待外部调用 notify 或 notifyAll 方法通知线程进入到 runable 就绪状态。
在A线程执行过程中,调用B线程的 join 方法后,在B线程执行完毕之前,A线程进入到 waiting 等地状态,等待B线程执行完毕后,自动通知A线程进入到 runable 就绪状态。
线程A、线程B,在争夺锁的过程,假如A先拿到锁,B就会进入到blocked,阻塞状态,等待A释放锁后,自己再去拿锁。
致谢
https://zhuanlan.zhihu.com/p/58966050
https://www.bilibili.com/video/BV1k74118721?t=513&p=24
https://blog.csdn.net/maoshaomiao/article/details/90756576