包括:
一. 线程创建方式(3种)
二. 线程常用API
三. 守护线程和非守护线程
四. 线程间的状态转换
一. 线程创建方式
线程创建有3种方式:
1. 通过继承 Thread 类,重写父类的 run() 方法。如下代码:
public class ThreadTest {
public static void main(String[] args) {
Thread thread = new MyThread();
thread.start();
}
}
class MyThread extends Thread{
@Override
public void run() {
System.out.println("This is my Thread");
}
}
2. 实现 Runnable 接口,实现其 run() 方法。如下代码:
public class ThreadTest {
public static void main(String[] args) {
Thread thread = new Thread(new MyThread());
thread.start();
}
}
class MyThread implements Runnable{
public void run() {
System.out.println("This is my Thread");
}
}
3. 实现 Callable 接口,实现其 call() 方法。代码如下:
public class ThreadTest {
public static void main(String[] args) {
MyThread thread = new MyThread();
try {
System.out.println(thread.call());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class MyThread implements Callable<Integer>{
@Override
public Integer call() throws Exception {
return 2;
}
}
Ps:Callable 和 Runnable 的区别:
- Callable 接口可以有返回值,Runnable 接口 没有返回值。
- Callable 接口主要通过实现其 call() 方法, Runnable 接口主要实现其 run() 方法。
二. 线程常用API
2.1 currentThread() 取得当前线程:
public static native Thread currentThread();
2.2 yield() 函数: 让当前运行的线程回到可运行的状态,以此运行具有相同优先级的其他线程获得运行机会。 但是,在实际中无法保证 yield() 达到让步的目的,因为让步的线程可能会被再次选中。
public static native void yield();
2.3 sleep(long millis) 函数:休眠几秒;start() 函数:开始执行线程;run() 函数:具体的执行的业务逻辑方法。
Ps:sleep 方法和wait 方法的区别:
sleep 方法不会释放对象锁。而 wait方法会释放对象锁。使用wait()方法之后,只有调用 notify() 或者 notifyAll()方法才能重新唤醒。
2.4 interrupt() 方法:中断一个线程。会把线程状态设置为"中断"状态。注意:线程中断仅仅是置线程的中断状态,而不会停止线程。
所以说,如果是普通使用interrupt() 方法,不加任何处理是无法中断一个线程的,如下代码:
public class ThreadTest {
public static void main(String[] args) {
Thread thread = new MyThread();
thread.start();
thread.interrupt();
}
}
class MyThread extends Thread{
public void run() {
int i = 0;
while(true){
System.out.println(i++);
}
}
}
输出结果会一直打印下去。此时需要结合 sleep 和 interruptedException。
public class ThreadTest {
public static void main(String[] args) {
Thread thread = new MyThread();
thread.start();
thread.interrupt();
}
}
class MyThread extends Thread{
public void run() {
try{
int i = 0;
while(true){
System.out.println(i++);
Thread.sleep(1);
}
} catch (InterruptedException ex){
System.out.println("catch exception");
}
}
}
另外,还有一种方式 则是 通过 Thread.interrupted() 函数,能够告诉你线程是否发生了中断,并将清除中断标志位。所以程序不会两次告诉你线程发生了中断。所以可以如下方式:
public class ThreadTest {
public static void main(String[] args) {
Thread thread = new MyThread();
thread.start();
thread.interrupt();
}
}
class MyThread extends Thread{
public void run() {
int i = 0;
while(!Thread.interrupted()){
System.out.println(i++);
}
}
}
2.4 interrupted() 方法:得知是否中断了一个线程。返回当前的线程中断状态。注意:如果线程中断,该方法第一次调用的时候会返回true,但是返回之后马上就会清除中断标志位,下次再调用就会返回false。
2.5 isInterrupted() 方法:会返回当前的中断状态。但是不会像 interrupted() 方法一样清除中断标志位。
2.6 join() 方法:主要是让一个线程 B 加入到线程A 的尾部。在 A 执行完之前, B不能工作。另外, join 还有带超时限制的重载版本。例如, t.join(5000)。 例如如下代码:
public class ThreadTest {
public static void main(String[] args) throws InterruptedException {
Thread thread = new MyThread();
thread.start();
thread.join();
for(int i = 0; i < 10; ++i){
System.out.println("main:" + i);
}
}
}
class MyThread extends Thread{
public void run() {
for(int i = 0; i < 10; ++i){
System.out.println("run:" + i);
}
}
}
三. 守护线程和非守护线程
Java中有两种线程,一种是守护线程,一种是非守护线程也就是用户线程。
守护线程 主要是用来服务非守护线程的,如果没有用户线程在执行,那么守护线程也不会存在,因为它也没有服务的对象。守护线程可以通过 setDaemon(boolean on) 的方式来进行设置,true 为 守护线程模式,false 为用户模式。
例如我们熟悉的垃圾回收线程就是一个典型的守护线程。
四. 线程间的状态转换
线程状态分为几种,新建,运行,阻塞,等待,有限等待,中止。如下图:
那么从new到running,调用start()方法。
从Running到waitiing,调用wait()方法。
那么从Running到Blocked,遇到synchronized等需要同步的块。
从Running到Timed Waitiing,调用sleep()方法。从Running到Terminated,则是run()方法执行结束。
参考:
- 用 interrupt() 中断 Java 线程:http://hapinwater.iteye.com/blog/310558
- java 线程 join 方法的使用:http://blog.sina.com.cn/s/blog_5c5bc9070100ytye.html