1.线程状态转换
状态 | 触发条件 | |
---|---|---|
WAITING | 当调用wait(),join(),LockSupport.lock()方法线程会进入到WAITING状态 | 另外当WAITING和TIMED _WAITING状态时可以通过Object.notify(),Object.notifyAll()方法使线程转换到Runable状态 |
TIMED_WAITING | 而同样的wait(long timeout),sleep(long),join(long),LockSupport.parkNanos(),LockSupport.parkUtil()增加了超时等待的功能,也就是调用这些方法后线程会进入TIMED_WAITING状态,当超时等待时间到达后,线程会切换到Runable的状态 | |
BLOCKED | 当线程出现资源竞争时,即等待获取锁的时候,线程会进入到BLOCKED阻塞状态,当线程获取锁时,线程进入到Runable状态。 | |
TERMINATED | 线程运行结束后,线程进入到TERMINATED状态 |
2.线程状态的基本操作
2.1 interrupted
2.2 join
两个好基友,一个基友先走在前面突然看见另一个基友落在后面了,这个时候他就会在原处等一等这个基友,等基友赶上来后,就两人携手并进。
如果一个线程实例A执行了threadB.join(),
其含义是:当前线程A会等待threadB线程终止后threadA才会继续执行。
2.2.1 方法关键
2.3 sleep
public static native void sleep(long millis)方法显然是Thread的静态方法,很显然它是让当前线程按照指定的时间休眠,其休眠时间的精度取决于处理器的计时器和调度器。需要注意的是如果当前线程获得了锁,sleep方法并不会失去锁。sleep方法经常拿来与Object.wait()方法进行比价,这也是面试经常被问的地方。
两者主要的区别:
- sleep()方法是Thread的静态方法,而wait是Object实例方法
- wait()方法必须要在同步方法或者同步块中调用,也就是必须已经获得对象锁。而sleep()方法没有这个限制可以在任何地方种使用。另外,wait()方法会释放占有的对象锁,使得该线程进入等待池中,等待下一次获取资源。而sleep()方法只是会让出CPU并不会释放掉对象锁;
- sleep()方法在休眠时间达到后如果再次获得CPU时间片就会继续执行,而wait()方法必须等待Object.notify/Object.notifyAll通知后,才会离开等待池,并且再次获得CPU时间片才会继续执行。
3.实现多线程的方式
3.1 实现Runnable接口
public class RunnableStyle implements Runnable {
@Override
public void run() {
System.out.println("1111");
}
public static void main(String[] args) {
RunnableStyle runnableStyle=new RunnableStyle();
Thread thread=new Thread(runnableStyle);
thread.start();
}
}
3.2 继承Thread类
public class ThreadStyle extends Thread {
@Override
public void run() {
System.out.println("1111");
}
public static void main(String[] args) {
ThreadStyle t1=new ThreadStyle();
Thread thread=new Thread(t1);
thread.start();
}
}
4.两者的区别
4.1 Thread 方式创建线程
Thread 内部 run()方法
/**
* If this thread was constructed using a separate
* <code>Runnable</code> run object, then that
* <code>Runnable</code> object's <code>run</code> method is called;
* otherwise, this method does nothing and returns.
* <p>
* Subclasses of <code>Thread</code> should override this method.
*
* @see #start()
* @see #stop()
* @see #Thread(ThreadGroup, Runnable, String)
*/
@Override
public void run() {
if (target != null) {
target.run();
}
}
以上ThreadStyle 继承Thread 类, 自定义的 run 方法**完全重写**Thread 内部中的run()方法
4.2 Runnable方式创建线程
以上RunnableStyle 实现Runnable 接口,作为Runnable 子类的形式 作为参数传入Thread 构造器中,本地方法注册后在相应平台创建好新线程后 回调 Thread中run()方法, target 为自定义Runnable子类,然后再调用子类实现的 run() 方法;
5.同时使用Thread 和Runnable 会发生什么?
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("我来自runnable");
}
} ){
@Override
public void run(){
System.out.println("我来自Thread");
}
}.start();
}
我来自Thread
因为 Thread 已经覆盖重写了 run 方法;
自问自答环节
1. Thread.start() 到底都干了啥,为啥能在不同的平台创建一个新的线程?
答案: java thread 类中 start()方法 在native中注册后,会到 hotspot jvm层面走流程,最终会回调 thread 中的run ()方法 执行业务流程。
从JVM层面了解线程的启动和停止