1、线程五种状态
- 新建状态(new):创建线程Thread对象进入新建状态。
- 就绪状态(runnable):调用start()方法,线程会进入就绪状态,如果得到CPU资源就会进入运行状态。
- 运行状态(running) :就绪状态得到 CPU 资源就会转为运行状态,执行 run() 方法,当调用 yield() 时线程会让步,从运行状态转到就绪状态,但该过程可能是及其短暂的,如果当前线程拥有较高优先级,即使让步后还是会进入运行状态
- 阻塞状态(blocked):会导致阻塞状态的方法主要有:sleep()、wait()、join()、等待获取锁、等待 I/O 等情况,在这些情况被处理后就会转为就绪状态,等待调度
- 终止状态(dead):线程销毁
2、线程方法
(1)线程常用方法
- start():使该线程开始执行,java虚拟机调用该线程的run()方法;
- run():如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。
- setName(String name):改变线程名称,使之与参数 name 相同。
- setPriority(int priority):更改线程的优先级。
- setDaemon(boolean on):将该线程标记为守护线程或用户线程。
- join(long millisec):等待该线程终止的时间最长为 millis 毫秒。把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程,比如在线程 B 中调用了线程 A 的 join() 方法,直到线程 A 执行完毕后才会继续执行线程 B。
- interrupt():中断线程。该方法直接对线程调用。当被interrupt的线程正在sleep或wait时,会抛出InterruptedException异常。
- isAlive():判断当前线程是否处于活动状态;
- yield():调用yield方法会让当前线程交出CPU权限,让CPU去执行其他的线程。它跟sleep方法类似,同样不会释放锁。但是yield不能控制具体的交出CPU的时间,另外,yield方法只能让拥有相同优先级的线程有获取CPU执行时间的机会。调用yield方法并不会让线程进入阻塞状态,而是让线程重回就绪状态,它只需要等待重新获取CPU执行时间,这一点是和sleep方法不一样的
- sleep(long millisec):在指定的毫秒数内让当前“正在执行的线程”休眠(暂停执行)。这个“正在执行的线程”是指this.currentThread()返回的线程。sleep方法不会释放锁,也就是说如果当前线程持有对某个对象的锁,则即使调用sleep方法,其他线程也无法访问这个对象。
- currentThread():可以返回代码段正在被哪个线程调用的信息。
- wait():使一个线程处于等待(阻塞)状态,并且释放所持有的对象的锁;
- notify():唤醒一个处于等待状态的线程,当然在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且与优先级无关;
- notityAll():唤醒所有处于等待状态的线程,该方法并不是将对象的锁给所有线程,而是让它们竞争,只有获得锁的线程才能进入就绪状态;
- 线程休眠和唤醒
public class MySleep {
public static void main(String[] args) throws InterruptedException {
sleepTest();
}
private static void sleepTest() throws InterruptedException {
Thread thread = new Thread() {
public void run() {
System.out.println("线程 " + Thread.currentThread().getName() + "将要休眠5分钟。");
try {
Thread.sleep(5 * 60 * 1000);
} catch (InterruptedException ex) {
System.out.println("线程 " + Thread.currentThread().getName() + "休眠被中断。");
}
System.out.println("线程 " + Thread.currentThread().getName() + "休眠结束。");
}
};
thread.setDaemon(true);
thread.start();
Thread.sleep(500);
thread.interrupt();
}
}
- 线程同步等待
public class MyJoin{
public static void main(String[] args) throws InterruptedException
{
joinTest();
}
private static void joinTest() throws InterruptedException
{
Thread thread = new Thread()
{
public void run()
{
try
{
for(int i = 0; i < 10; i++)
{
System.out.println("线程在运行---"+i);
Thread.sleep(1000);
}
}
catch(InterruptedException ex)
{
ex.printStackTrace();
}
}
};
thread.setDaemon(true);
thread.start();
thread.join();
System.out.println("主线程正常结束。");
}
}
- 线程终止
public class MyInterrupt{
public static void main(String[] args)
{
stopTest();
}
private static void stopTest()
{
Thread thread = new Thread()
{
public void run()
{
System.out.println("线程运行。");
try {
Thread.sleep(1*60*1000);
} catch (InterruptedException e) {
System.out.println("线程中断,结束线程");
return ;
}
System.out.println("线程正常结束");
}
};
thread.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();
}
}
总结
1、线程的sleep()方法和yield()方法有什么区别?
(1)线程执行sleep()方法后转入阻塞(blocked)状态,而执行yield()方法后转入就绪(ready)状态;
(2)sleep()方法声明抛出InterruptedException,而yield()方法没有声明任何异常;
(3)sleep()方法不考虑优先级,yield()方法只会给相同优先级或更高优先级的线程以运行的机会;
2、线程的sleep()方法和wait()方法有什么区别?
(1)sleep()方法(休眠)是线程类(Thread)的静态方法,调用此方法会让当前线程暂停执行指定的时间,将执行机会(CPU)让给其他线程,但是对象的锁依然保持,因此休眠时间结束后会自动恢复。
(2)wait()是Object类的方法,调用对象的wait()方法导致当前线程放弃对象的锁(线程暂停执行),进入对象的等待池(wait pool),只有调用对象的notify()方法(或notifyAll()方法)时才能唤醒等待池中的线程进入等锁池(lock pool),如果线程重新获得对象的锁就可以进入就绪状态。
3、守护线程与用户线程的区别?
守护线程和用户线程的区别在于:守护线程依赖于创建它的线程,而用户线程则不依赖。举个简单的例子:如果在main线程中创建了一个守护线程,当main方法运行完毕之后,守护线程也会随着消亡。而用户线程则不会,用户线程会一直运行直到其运行完毕。在JVM中,像垃圾收集器线程就是守护线程。