线程的概念及疑问
- 进程和线程
进程是一个静态的概念,机器上的一个class文件,程序要执行,首先要把class文件加载进内存,加载后并未执行,进程已经产生了。进程开始执行是指主方法(main方法)执行了,实际上运行的都是线程。 - 通过Runnable接口创建线程
public class TestThread1 {
public static void main(String args[]) {
Runner r = new Runner();
Thread t = new Thread(r); //主线程;
t.start(); //启动分支线程
for(int i=0; i<100; i++) {
System.out.println("Main Thread:----" + i);
}
}
}
class Runner implements Runnable {
public void run() { //线程运行体;
for(int i=0; i<100; i++) {
System.out.println("Runner1 :" + i);
}
}
}
- 继承Thread类创建线程
public class TestThread1_2{
public static void main(String arg[]){
Runner1_2 r = new Runner1_2();
r.start();
for (int i = 0 ;i <= 100; i++){
System.out.println("Main Thread:!!!!"+i);
}
}
}
class Runner1_2 extends Thread{
public void run(){
for (int i = 0 ;i <= 100; i++){
System.out.println("Runner2:!!!!"+i);
}
}
}
- 上面2个程序运行结果的分析
上面2个程序允许的时候会发现,原先我们的程序都是看起来都是顺序执行的
,当我们启动一个线程后会出现main线程和我们启动的新线程交替执行的现象。可以看出CPU有一个调度的过程,多个线程都获得了执行的机会。 - 单独执行调用run方法是不会启动一个新的线程的。
public class TestThread1_1 {
public static void main(String args[]) {
Runner r = new Runner();
Thread t = new Thread(r);
t.run(); //这里不会启动一个分支线程,也不会有交替获得时间片的情况
for(int i=0; i<100; i++) {
System.out.println("Main Thread:----" + i);
}
}
}
class Runner implements Runnable {
public void run() { //线程运行体;
for(int i=0; i<100; i++) {
System.out.println("Runner1 :" + i);
}
}
}
线程的状态
Thread states and life cycle in Java
(来源: https://www.uml-diagrams.org/java-thread-uml-state-machine-diagram-example.html)
线程状态的文字描述
- New : 线程对象被创建后,就进入了新建状态。例如,Thread thread = new Thread()。
- Runnable:(2-1 Ready) 线程对象被创建后,其它线程调用了该对象的start()方法,从而来启动该线程。例如,thread.start()。处于就绪状态的线程,随时可能被CPU调度执行。 (2-2 Running)运行状态() : 线程获取CPU的时间片。需要注意的是,线程只能从就绪状态进入到运行状态。
- 线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。
(https://dzone.com/articles/difference-between-blocked-waiting-timed-waiting-e 线程几种状态的解释)
3.1 Blocked
Java doc formally defines BLOCKED state as: “A thread that is blocked waiting for a monitor lock is in this state.”
Real-life example: Today you are going for a job interview. This is your dream job, which you have been targeting for last few years. You woke up early in the morning, got ready, put on your best outfit, looking sharp in front of the mirror. Now you step out to your garage and realize that your wife has already taken the car. In this scenario, you only have one car, so what will happen? In real life, a fight may happen :-). Here you are BLOCKED because your wife has already taken the car. You won't be able to go to the interview.
This is the BLOCKED state. Explaining it in technical terms, you are the thread T1 and your wife is the thread T2 and lock is the car. T1 is BLOCKED on the lock (i.e. the car), because T2 has already acquired this lock.
Titbit: A Thread will enter in to BLOCKED state when it’s waiting for a monitor lock to enter a synchronized block/method or reenter a synchronized block/method after calling Object#wait() method.
3.2 Waiting
Java doc formally defines WAITING state as: “A thread that is waiting indefinitely for another thread to perform a particular action is in this state.”
Real-life example: Let’s say few minutes later your wife comes back home with the car. Now you realize that the interview time is approaching, and there is a long distance to drive to get there. So, you put all the power on the gas pedal in the car. You drive at 100 mph when the allowed speed limit is only 60 mph. Your luck, a traffic cop sees you driving over the speed limit, and he pulls you over to the curb. Now you are entering into the WAITING state, my friend. You stop driving the car and sit idly in the car until the cop investigates you, and then lets you go. Basically, until he lets you go, you are stuck in the WAITING state.
Explaining it in technical terms, you are thread T1 and the cop is thread T2. You released your lock (i.e. you stopped driving the car), and went into the WAITING state. Until the cop (i.e. T2) lets you go, you will be stuck in this WAITING state.
Titbit: A Thread will enter in to WAITING state when it’s calling one of the following methods:
Object#wait() with no timeout (没有时间参数)
Thread#join() with no timeout (没有时间参数)
LockSupport#park()
Thread that has called Object.wait() on an object is in WAITING state until another thread to call Object.notify() or Object.notifyAll() on that object. A thread that has called Thread.join() is in WAITING state for a specified thread to terminate.
3.3 Timed Waiting
Java doc formally defines TIMED_WAITING state as: “A thread that is waiting for another thread to perform an action for up to a specified waiting time is in this state.”
Real-life example: Despite all the drama, you did extremely well in the interview, impressed everyone and got this high paying job. (Congratulations!) You come back home and tell to your neighbor about this new job and how excited you are about it. Your friend says that he is also working in the same office building. He suggests that the two of you should drive together. You think it’s a great idea. So on the first day of work, you go to his house. You stop your car in front of his house. You wait for 10 minutes, but your neighbor still doesn’t come out. You go ahead and start driving to work, as you don’t want to be delayed on your first day. Now this is TIMED_WAITING.
Explaining it in technical terms, you are thread T1 and your neighbor is thread T2. You release lock (i.e. stop driving the car) and wait up to 10 minutes. If your neighbor, T2, doesn’t come out in 10 minutes, you start driving the car again.
Titbit: A Thread will enter in to TIMED_WAITING state when it’s calling one of the following methods:
Thread#sleep()
Object#wait() with timeout
Thread#join() with timeout
LockSupport#parkNanos()
LockSupport#parkUntil()
3.4 Conclusion
When someone is analyzing thread dumps, understanding these different thread states are critical. How many threads are in RUNNABLE, BLOCKED, WAITING, and TIMED_WATING states? Which threads are blocked? Who is blocking them? What object used for locking? These are some of the important metrics to be analyzed in thread dumps. These kinds of detailed thread dump analyses can easily be done through an online tool such as: http://fastthread.io/
4.常见的几种阻塞的描述
(01) 等待阻塞 -- 通过调用线程的wait()方法,让线程等待某工作的完成。
(02) 同步阻塞 -- 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态。
(03) 其他阻塞 -- 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
- 死亡状态(terminated) : 线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
线程控制的基本方法
- isAlive() :判断线程是否还活着,即线程是否还未中止。
- getPriority(),setPriority():获取/设置线程的优先级。
- Thread.sleep():设置当前线程睡眠指定的毫秒数。
- join():调用某线程的该方法,将当前线程与该线程合并,即等待该线程结束,再恢复当前线程的执行。
- yield():让出CPU,当前线程进入就绪队列等待调度。
- wait():当前线程进入对象的wait pool.
- notify(),notifyAll():唤醒对象的wait pool中的一个/所有等待线程。
- run()
- Thread.interrupt()
- stop()
sleep() & interrupt()
import java.util.*;
public class TestInterrupt {
public static void main(String arg[]){
MyThread thread = new MyThread();
thread.start();
try{
Thread.sleep(10000);
} //主线程睡眠…
catch(InterruptedException e){
}
thread.interrupt(); //中断线程。
}
}
class MyThread extends Thread{
boolean flag = true;
public void run(){ //重写的方法不能抛出不必被重写方法不同的方法,此处不能写throws InterruptedException
while(flag){
System.out.println("----"+ new Date()+"----");
try{
sleep(1000);
}
catch(InterruptedException e){ //捕获抛出的异常
return; //停止
}
}
}
}
----Mon Jul 02 00:19:28 CST 2018----
----Mon Jul 02 00:19:29 CST 2018----
----Mon Jul 02 00:19:30 CST 2018----
----Mon Jul 02 00:19:31 CST 2018----
----Mon Jul 02 00:19:32 CST 2018----
----Mon Jul 02 00:19:33 CST 2018----
----Mon Jul 02 00:19:34 CST 2018----
----Mon Jul 02 00:19:35 CST 2018----
----Mon Jul 02 00:19:36 CST 2018----
----Mon Jul 02 00:19:37 CST 2018----
join
public class TestJoin {
public static void main(String[] args) {
MyThread2 t1 = new MyThread2("abcde");
t1.start();//启动分支线程
try {
t1.join();//把T1分支线程合并到当前线程,这样当前线程会等待T1执行完成再继续执行
} catch (InterruptedException e) {}
for(int i=1;i<=10;i++){
System.out.println("i am main thread");
}
}
}
class MyThread2 extends Thread {
MyThread2(String s){
super(s);
}
public void run(){
for(int i =1;i<=10;i++){
System.out.println("i am "+getName());
try {
sleep(1000); //制造一种一秒打印一次的效果
} catch (InterruptedException e) {
return;
}
}
}
}
i am abcde
i am abcde
i am abcde
i am abcde
i am abcde
i am abcde
i am abcde
i am abcde
i am abcde
i am abcde
i am main thread
i am main thread
i am main thread
i am main thread
i am main thread
i am main thread
i am main thread
i am main thread
i am main thread
i am main thread
将MyThread2 中run方法中的for循环的10改为100,然后会打印会所有的i am abcde,下面才会打印i am main thread。