Contents
  1. 1. 参考:
  2. 2. Thread类中常用的方法:
    1. 2.1. 1)start方法
    2. 2.2. 2)run方法
    3. 2.3. 3)sleep方法
    4. 2.4. 4)yield方法(让步方法)
    5. 2.5. Sleep(),wait(),yield()方法的比较:
    6. 2.6. 5)join方法
    7. 2.7. 6)interrupt方法
  3. 3. 以下是关系到线程属性的几个方法:

参考:

http://www.cnblogs.com/dolphin0520/p/3920357.html
http://www.cnblogs.com/skywang12345/p/3479256.html

  Thread类实现了Runnable接口,在Thread类中,有一些比较关键的属性,比如name是表示Thread的名字,可以通过Thread类的构造器中的参数来指定线程名字,priority表示线程的优先级(最大值为10,最小值为1,默认值为5),daemon表示线程是否是守护线程,target表示要执行的任务。

Thread类中常用的方法:

1)start方法

  start()用来启动一个新的线程,当调用start方法后,系统才会开启一个新的线程来执行用户定义的子任务,在这个过程中,会为相应的线程分配需要的资源。

2)run方法

  run()方法是不需要用户来调用的,当通过start方法启动一个线程之后,当线程获得了CPU执行时间,便进入run方法体去执行具体的任务。注意,直接调用run()方法会直接在当前线程中运行run()方法,而不会启动一个新的线程运行run()方法

3)sleep方法

1
2
3
4
sleep方法有两个重载版本:
sleep(long millis) //参数为毫秒

sleep(long millis,int nanoseconds) //第一参数为毫秒,第二个参数为纳秒

(1)sleep相当于让线程睡眠,交出CPU,让CPU去执行其他的任务。Thread.currentThread().sleep(1000);
(2)sleep方法不会释放锁,也就是说如果当前线程持有对某个对象的锁,则即使调用sleep方法,其他线程也无法访问这个对象。
(3)当前线程会从“运行状态”进入到“休眠(阻塞)状态”
看下面这个例子就清楚了:


  从上面输出结果可以看出,当Thread-0进入睡眠状态之后,Thread-1并没有去执行具体的任务。只有当Thread-0执行完之后,此时Thread-0释放了对象锁,Thread-1才开始执行。
  注意,如果调用了sleep方法,必须捕获InterruptedException异常或者将该异常向上层抛出。当线程睡眠时间满后,不一定会立即得到执行,因为此时可能CPU正在执行其他的任务。所以说调用sleep方法相当于让线程进入阻塞状态。

4)yield方法(让步方法)

  调用yield方法会让当前线程交出CPU权限,让CPU去执行其他的线程。它跟sleep方法类似,同样不会释放锁。但是yield不能控制具体的交出CPU的时间,另外,yield方法只能让拥有相同优先级的线程有获取CPU执行时间的机会。

注意,调用yield方法并不会让线程进入阻塞状态,而是让线程重回就绪状态,它只需要等待重新获取CPU执行时间,这一点是和sleep方法不一样的。

Sleep(),wait(),yield()方法的比较:

(01) sleep()、wait()是让线程由“运行状态”进入到“等待(阻塞)状态”,而yield()是让线程由“运行状态”进入到“就绪状态”。
(02) wait()是会线程释放它所持有对象的同步锁,而yield(),sleep()方法不会释放锁。

5)join方法

join() 的作用:让“主线程”等待“子线程”结束之后才能继续运行。

1
2
3
4
join方法有三个重载版本:
join()
join(long millis) //参数为毫秒
join(long millis,int nanoseconds) //第一参数为毫秒,第二个参数为纳秒

  假如在main线程中,调用thread.join方法,则main方法会等待thread线程执行完毕或者等待一定的时间。如果调用的是无参join方法,则等待thread执行完毕,如果调用的是指定了时间参数的join方法,则等待一定的时间。

实际上调用join方法是调用了Object的wait方法,这个可以通过查看源码得知:

wait方法会让线程进入阻塞状态,并且会释放线程占有的锁,并交出CPU执行权限。

由于wait方法会让线程释放对象锁,所以join方法同样会让线程释放对一个对象持有的锁。

6)interrupt方法

interrupt,顾名思义,即中断的意思。单独调用interrupt方法可以使得处于阻塞状态的线程抛出一个异常,(非阻塞状态可以用isInterrupted()方法判断中断标记然后进行中断操作),也就说,它可以用来中断一个正处于阻塞状态的线程(并不是直接中断,而是修改判断中断的那个标记);或通过interrupt方法和isInterrupted()方法来停止正在运行的线程。

(1)通过“中断”方式终止处于“阻塞状态”的线程。
当线程由于被调用了sleep(), wait(), join()等方法而进入阻塞状态;若此时调用线程的interrupt()将线程的中断标记设为true。由于处于阻塞状态,中断标记会被清除,同时产生一个InterruptedException异常。将InterruptedException放在适当的为止就能终止线程,形式如下:

1
2
3
4
5
6
7
8
9
10
@Override
public void run() {
try {
while (true) {
// 执行任务...
}
} catch (InterruptedException ie) {
// 由于产生InterruptedException异常,退出while(true)循环,线程终止!
}
}

说明:在while(true)中不断的执行任务,当线程处于阻塞状态时,调用线程的interrupt()产生InterruptedException中断。中断的捕获在while(true)之外,这样就退出了while(true)循环!
注意:对InterruptedException的捕获务一般放在while(true)循环体的外面,这样,在产生异常时就退出了while(true)循环。否则,InterruptedException在while(true)循环体之内,就需要额外的添加退出处理。

(2) 通过“中断标记”终止运行状态的线程。
形式如下:

1
2
3
4
5
6
@Override
public void run() {
while (!isInterrupted()) {
// 执行任务...
}
}

说明:isInterrupted()是判断线程的中断标记是不是为true。当线程处于运行状态,并且我们需要终止它时;可以调用线程的interrupt()方法,使用线程的中断标记为true,即isInterrupted()会返回true。此时,就会退出while循环。 或者判断如果isInterrupted()返回的是true则return。

注意:interrupt()并不会终止处于“运行状态”的线程!它会将线程的中断标记设为true。

(3) 通过“额外添加标记”终止运行状态的线程。
形式如下:

1
2
3
4
5
6
7
8
9
10
11
private volatile boolean flag= true;
protected void stopTask() {
flag = false;
}

@Override
public void run() {
while (flag) {
// 执行任务...
}
}

说明:线程中有一个flag标记,它的默认值是true;并且我们提供stopTask()来设置flag标记。当我们需要终止该线程时,调用该线程的stopTask()方法就可以让线程退出while循环。
注意:将flag定义为volatile类型,是为了保证flag的可见性。即其它线程通过stopTask()修改了flag之后,本线程能看到修改后的flag的值。

1
2
3
4
5
运行结果:

进入睡眠状态
得到中断异常
run方法执行完毕

  从这里可以看出,通过interrupt方法和isInterrupted()方法一起使用来中断处于阻塞状态的线程(在catch代码块中return)。那么能不能中断处于非阻塞状态的线程呢?看下面这个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Test {

public static void main(String[] args) throws IOException {
Test test = new Test();
MyThread thread = test.new MyThread();
thread.start();
try {
Thread.currentThread().sleep(2000);
} catch (InterruptedException e) {

}
thread.interrupt();
}

class MyThread extends Thread{
@Override
public void run() {
int i = 0;
while(i<Integer.MAX_VALUE){
System.out.println(i+" while循环");
i++;
}
}
}
}

  运行该程序会发现,while循环会一直运行直到变量i的值超出Integer.MAX_VALUE。所以说直接调用interrupt方法不能中断正在运行中的线程。
  但是如果配合isInterrupted()能够中断正在运行的线程,因为调用interrupt方法相当于将中断标志位置为true,那么可以通过调用isInterrupted()判断中断标志是否被置位来中断线程的执行。比如下面这段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
	public class Test {

public static void main(String[] args) throws IOException {
Test test = new Test();
MyThread thread = test.new MyThread();
thread.start();
try {
Thread.currentThread().sleep(2000);
} catch (InterruptedException e) {

}
thread.interrupt();
}

class MyThread extends Thread{
@Override
public void run() {
int i = 0;
while(!isInterrupted() && i<Integer.MAX_VALUE){
System.out.println(i+" while循环");
i++;
}
}
}
}

  运行会发现,打印若干个值之后,while循环就停止打印了。
但是一般情况下不建议通过这种方式来中断线程,一般会在MyThread类中增加一个属性 isStop来标志是否结束while循环,然后再在while循环中判断isStop的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class MyThread extends Thread{
private volatile boolean isStop = false;
@Override
public void run() {
int i = 0;
while(!isStop){
i++;
}
}

public void setStop(boolean stop){
this.isStop = stop;
}
}

  那么就可以在外面通过调用setStop方法来终止while循环。

以下是关系到线程属性的几个方法:

1
2
3
4
5
6
7
8
9
10
11
  1)getId
  用来得到线程ID

  2)getName和setName
  用来得到或者设置线程名称。

  3)getPriority和setPriority
  用来获取和设置线程优先级。

  4)setDaemon和isDaemon
用来设置线程是否成为守护线程和判断线程是否是守护线程。该方法必须在启动线程前调用。

守护线程和用户线程的区别在于:守护线程依赖于创建它的线程,而用户线程则不依赖。举个简单的例子:如果在main线程中创建了一个守护线程,当main方法运行完毕之后,守护线程也会随着消亡。而用户线程则不会,用户线程会一直运行直到其运行完毕。在JVM中,像垃圾收集器线程就是守护线程。

Contents
  1. 1. 参考:
  2. 2. Thread类中常用的方法:
    1. 2.1. 1)start方法
    2. 2.2. 2)run方法
    3. 2.3. 3)sleep方法
    4. 2.4. 4)yield方法(让步方法)
    5. 2.5. Sleep(),wait(),yield()方法的比较:
    6. 2.6. 5)join方法
    7. 2.7. 6)interrupt方法
  3. 3. 以下是关系到线程属性的几个方法: