一、生命周期
1、当新建(new Thread)一个线程时,便进入新建的状态。
2、当线程调用start()方法后便进入就绪状态,进入线程池,等待系统调用。
3、系统空闲时,便会从线程池当中取出该线程运行执行run()方法,此过程不受程序控制。
4、运行中的线程调用yield()方法便会返回就绪状态。
5、运行中的线程执行sleep()方法、线程等待一个异步的操作结果(如等待某个notify)、线程调用了suspend方法(已过时)就会进入阻塞状态。
6、run()方法结束后,线程死亡,或者调用了stop()(已过时)、destory()(已过时)方法。
二、常见操作(sleep、wait、yield、join、interrupt、setDaemon、setPriority)
在API文档中可以查看到很多对线程操作的方法,但是有很多已经Deprecated,需要熟悉的方法就是sleep、wait、yield、join、setDaemon、setPriority等。
1、sleep()方法,进程休眠程序,调用此方法后,进程进入阻塞状态,休眠时间到了,便会从新运行。
eg1:
public class test5 {
public static void main(String args[]){
for( int i = 0 ; i < 100 ; i++){
System. out.println( "helloworld");
try {
Thread. sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
此程序每隔1s打印一次helloworld。
注:
由于系统不一定就能在休眠时间到了就立即恢复程序的执行,所以间隔时间往往是大于1秒的。
sleep函数必须写在线程本身的run()方法中,才能保证在该线程执行过程中睡眠。
VIP:sleep是静态方法(不需要实例化就能使用),最好不要用Thread的实例对象调用它,因为它睡眠的始终是当前正在运行的线程,而不是调用它的线程对象,它只对正在运行状态的线程对象有效,不属于某一个特定的线程实例。
eg2:
MyThread myThread = new MyThread();
try {
myThread.sleep(10000);//在这里,实际上睡眠的是主线程
} catch (InterruptedException e) {
e. printStackTrace();
}
2、yield()方法,线程让步方法,执行该方法后,线程重新返回就绪状态,等待系统重新调用。
eg3:
class MyThread extends Thread{
String str;
public MyThread(String str) {
// TODO Auto-generated constructor stub
this. str = str;
}
@Override
public void run() {
// TODO Auto-generated method stub
for( int i = 0; i<100; i++ ){
System. out.println( str + "第" +i + "次");
try {
sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
super.run();
}
}
class MyThread2 extends Thread{
String str;
public MyThread2(String str) {
// TODO Auto-generated constructor stub
this. str = str;
}
@Override
public void run() {
// TODO Auto-generated method stub
for( int i = 0; i<100; i++ ){
if(i%2==0){
this .yield();
}
System. out.println( str + "第" +i + "次");
try {
sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
super.run();
}
}
public class test5 {
public static void main(String args[]){
MyThread firstThread = new MyThread( "this is firstThread");
MyThread2 secondThread = new MyThread2( "this is secondThread");
secondThread.start();
firstThread.start();
}
}
执行该方法后,可以看到当i是偶数的,基本上都是firstThread先执行。
总结与sleep()方法的区别,返回线程状态不同,sleep需要catch InterruptedException 的异常。
3、join()方法
当线程2必须等线程1执行完了再执行时,就可以合并这两个线程为一个线程,使用join方法完成操作。
eg4:
public class test6 {
public static void main(String[] args) throws InterruptedException {
MyThread3 thread= new MyThread3();
thread.start();
thread.join(1); //将主线程加入到子线程后面,不过如果子线程在1毫秒时间内没执行完,则主线程便不再等待它执行完,进入就绪状态,等待 cpu调度
for( int i=0;i<30;i++){
System. out.println(Thread. currentThread().getName() + "线程第" + i + "次执行!" );
}
}
}
class MyThread3 extends Thread {
@Override
public void run() {
for ( int i = 0; i < 1000; i++) {
System. out.println( this.getName() + "线程第" + i + "次执行!" );
}
}
}
结果:
4、setPriority()方法,除了可以使用sleep、yield方法一定程序上(精确的控制不能实现,是由系统决定的)控制线程执行的先后顺序,还有使用设置优先级的方法。
eg5:
class thread01 extends Thread{
thread01( int por){
this.setPriority(por);
}
@Override
public void run() {
for( int i = 0; i<100; i++){
System. out.println( "thread01");
}
super.run();
}
}
class thread02 extends Thread{
thread02( int por){
this.setPriority(por);
}
@Override
public void run() {
for( int i = 0; i<100; i++){
System. out.println( "thread02");
}
super.run();
}
}
public class test7 {
public static void main(String[] agrs){
thread01 t01 = new thread01(1);
thread02 t02 = new thread02(10);
t01.start();
t02.start();
}
}
可以看到,在t01执行完了之后,t02才执行。
5、setDaemon方法,设置线程为守护线程,守护线程的优先级一般是比用户线程的优先级低的。详见(Java线程的概念、创建与启动(一))。