您的位置:首页 > 编程语言 > Java开发

Java并发编程(一)——线程

2016-03-21 11:41 253 查看

Java并发编程(一)——线程

一,线程的实现方式

  Java中实现多线程有两种方式,如下:

1,继承java.lang.Thread类,重写run()方法;
2,实现java.lang.Runnable接口,重写接口中的run()方法。


  这两种实现方式没有优劣,但由于Java中不允许多继承,所以使用第二种实现接口的方式更加灵活。

  另外需要注意的是实现了Runnable的类,就像其字面描述的意思一样,只是一个可运行的东西,最终也是要Thread类来启动它,它才能跑起来。这一点从源码上分析来看,只能说Runnable接口只是为了用来在不能多继承的情况下来实现多线程而设计的,最终线程的内容和启动还是Thread来实现的。

  代码如下:

public class ThreadDemo {
public static void main(String[] args) {
Thread t = new Thread();
t.start();

Thread t2 = new Thread(new Line());
t2.start();
}
}
class Line implements Runnable{

@Override
public void run() {
System.out.println("Line Thread is running...");
}
}


  而更多的情况下,我们会采用匿名内部类来实现多线程:

public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("I'm a new Thread");
}
}).start();
}


二,线程的生命周期

  线程的生命周期是指一个线程从创建到消亡的过程。

新建状态(New)

  当用new操作符创建一个新的线程对象时,该线程处于创建状态。处于创建状态的线程只是一个空的线程对象,系统不为它分配资源。

注意:不能对已经启动的线程再次调用start()方法,否则会出现java.lang.IllegalThreadStateException异常。如下:

Thread t = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("I'm a new Thread");
}
});
t.start();
t.start();//同一个(同id)线程不能同时启动两次


另,线程是不能clone的,因为线程id是不能重复的,会抛出CloneNotSupportedException异常,见源码:

@Override
protected Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}


就绪状态(Runnable)

  线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。

运行状态(Running)

  就绪状态的线程获取了CPU的使用权,执行程序代码的过程就处于运行态。

阻塞状态(Blocked)

  阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:

(1)等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。

(2)同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。

(3)其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

死亡状态(Dead)

  线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

三,线程状态的转换

1,线程生命周期图





2,线程状态的切换方式:

1)yield():yield的意思是让步,让出,就是暂时让出CPU的使用权,所以从Running变为了Runnable状态。

2)sleep():使线程睡眠一定的时间,由Running态变为Blocked态。

3)join():使当前线程(如主线程)挂起,直到调用join方法的线程执行完毕。

4)exit():在线程进入Running之前可以清空并退出该线程。

5)stop():强制线程退出,
已废弃


6)suspend():挂起线程,由Running变为Blocked,和resume相对应,
已废弃


7)resume():恢复线程,由Blocked变为Runnable,
已废弃


8)interrupt():打断/中断线程。

四,Thread类的常用API

void setName(String name)
:为线程设置线程名;

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

void setDaemon(boolean on)
:设置是否是守护线程,是谁的守护线程?是当前线程的守护线程;需要在start方法调用之前使用;另,在Daemon线程中产生或新建的新线程默认也是Daemon的。

public class DaemonDemo {

public static void main(String[] args) throws InterruptedException {
TestThread test = new TestThread();
// 如果不设置daemon,那么线程将输出10后才结束
test.setDaemon(true);
test.start();
System.out.println("isDaemon = " + test.isDaemon());
try {
System.in.read(); // 接受输入,使程序在此停顿,一旦接收到用户输入,main线程结束,守护线程自动结束
} catch (IOException ex) {
ex.printStackTrace();
}
}
}

class TestThread extends Thread {
public void run() {
for (int i = 1;; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
System.out.println(i);
}
}
}


boolean isDaemon()
:判断是否是守护线程;

void setPriority(int newPriority)
:设置线程优先级,默认为5,最小为1,最大为10;优先级越高,越能更早的获取CPU调度;

Thread currentThread()
:返回当前线程对象的一个引用,为什么不用this?见下篇博客

int activeCount()
:返回当前线程所在的线程组中活跃线程的数量;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 多线程