线程的状态
- NEW至(至今尚未启动的线程)
- RUNNABLE(JVM正在执行的线程)
- BLOCKED(受阻塞并等待某个监视器锁的线程)
- WAITING(等待唤醒的线程)
- TIMED_WAITING(线程等待状态,等待CPU时间)
- TERMINATED(已退出的线程)
代码6-1
class StateDemo extends Thread {
@Override
public void run() {
try {
System.out.println("demo线程运行" );
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class ThreadState {
public static void main(String[] args) throws InterruptedException {
StateDemo demo = new StateDemo();
System.out.println("demo初始化线程状态:"+demo.getState());
demo.start();
System.out.println("demo调用start()后线程状态:"+demo.getState());
Thread.sleep(1000);
System.out.println("demo线程休眠2s线程状态:"+demo.getState());
Thread.sleep(3000);
System.out.println("demo线程执行完毕线程状态:"+demo.getState());
}
}
代码6-1执行结果:
demo初始化线程状态:NEW
demo调用start()后线程状态:RUNNABLE
demo线程运行
demo线程休眠2s线程状态:TIMED_WAITING
demo线程执行完毕线程状态:TERMINATED
初始化Demo对象,尚未调用start()方法时,线程状态为NEW新建状态,调用start()方法后,线程由新建态转为RUNNABLE就绪态,CPU是时间分配给demo线程,而后demo线程休眠,此时线程状态为TIMED_WAITING休眠态,最后线程执行完run()方法后,线程状态为TERMINATED死亡态。
BLOCKED状态出现在某一个线程在等待锁的时候
代码6-2
class CountThread extends Thread {
private CalCount cal;
public CountThread(CalCount cal) {
super();
this.cal = cal;
}
@Override
public void run() {
cal.add();
}
}
public class CalCount {
private static int count = 0;
public synchronized void add() {
try {
count++;
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public synchronized int getCount() {
return count;
}
public static void main(String[] args) {
CalCount calCount = new CalCount();
CountThread cal1 = new CountThread(calCount);
CountThread cal2 = new CountThread(calCount);
try {
cal1.start();
Thread.sleep(100);
cal2.start();
Thread.sleep(100);
System.out.println("cal2线程状态:" + cal2.getState());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
代码6-2运行结果:
cal2线程状态:BLOCKED
cal2等待cal1释放锁的时候,线程状态为BLOCKED
状态WAITING是线程执行了Object.wait()后所处的状态
代码6-3
class WaitThread extends Thread {
@Override
public void run() {
synchronized (WaitQueue.LOCK) {
try {
WaitQueue.LOCK.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public class WaitQueue {
public static final String LOCK = "LOCK";
public static void main(String[] args) {
WaitThread w1 = new WaitThread();
WaitThread w2 = new WaitThread();
try {
w1.start();
w2.start();
Thread.sleep(500);
System.out.println("w1线程状态:" + w1.getState());
System.out.println("w2线程状态:" + w2.getState());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (WaitQueue.LOCK) {
WaitQueue.LOCK.notifyAll();
}
try {
Thread.sleep(500);
System.out.println("w1线程状态:" + w1.getState());
System.out.println("w2线程状态:" + w2.getState());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
代码6-3运行结果:
w1线程状态:WAITING
w2线程状态:WAITING
w1线程状态:TERMINATED
w2线程状态:TERMINATED
线程组
可以把线程归属到某一个线程组,线程组中可以有线程对象,也可以有线程组,组中还可以有线程
代码6-4
public class ThreadGroupJoin {
public static void main(String[] args) {
ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();
// 将组A归入main线程组中
ThreadGroup group = new ThreadGroup(mainGroup, "A");
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
System.out.println("run method()");
Thread.sleep(1000);// 线程必须在运行状态才可以受组管理
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
Thread newThread = new Thread(group, runnable);
newThread.setName("new-thread");
newThread.start();// 线程必须启动然后才归到组A中
ThreadGroup[] listGroups = new ThreadGroup[Thread.currentThread().getThreadGroup().activeGroupCount()];
// 列举当前线程组中的子线程组
Thread.currentThread().getThreadGroup().enumerate(listGroups);
System.out.println("main线程组中有" + listGroups.length + "个线程组,线程组名称为:" + listGroups[0].getName());
Thread[] listThread = new Thread[listGroups[0].activeCount()];
listGroups[0].enumerate(listThread);
System.out.println("线程名为:" + listThread[0].getName());
}
}
代码6-4运行结果:
main线程组中有1个线程组,线程组名称为:A
run method()
线程名为:new-thread
线程组自动归属到当前线程组中
代码6-5
public class AutoJoin {
public static void main(String[] args) {
System.out.print("线程名称:" + Thread.currentThread().getName());
System.out.print("\t线程组名称:" + Thread.currentThread().getThreadGroup().getName());
System.out.println("\t线程组数量:" + Thread.currentThread().getThreadGroup().activeGroupCount());
// 创建新的线程组
ThreadGroup group = new ThreadGroup("sub-group");
System.out.println("—————————————————————");
System.out.print("线程名称:" + Thread.currentThread().getName());
System.out.print("\t线程组名称:" + Thread.currentThread().getThreadGroup().getName());
System.out.println("\t线程组数量:" + Thread.currentThread().getThreadGroup().activeGroupCount());
}
}
代码6-5运行结果:
线程名称:main 线程组名称:main 线程组数量:0
—————————————————————
线程名称:main 线程组名称:main 线程组数量:1
从运行结果可以看出,在实例化一个线程组group时,如果不指明所属线程组,group将自动归到当前线程对象所属的线程组中。
获取根线程组
代码6-6
public class ParentThreadGroup {
public static void main(String[] args) {
Thread mainThread = Thread.currentThread();
System.out.print("mainThread 线程组名称:" + mainThread.getThreadGroup().getName());
System.out.print("\t\t线程组数量:" + mainThread.getThreadGroup().activeGroupCount());
System.out.print("\t\t父线程组名称:" + mainThread.getThreadGroup().getParent().getName());
System.out.println("\t\t父线程组数量:" + mainThread.getThreadGroup().getParent().activeGroupCount());
System.out.println("————————————————————————————————————————————");
ThreadGroup group = new ThreadGroup("new-group");
System.out.print("group 线程组名称:" + group.getName());
System.out.print("\t\t线程组数量:" + group.activeGroupCount());
System.out.print("\t\t父线程组名称:" + group.getParent().getName());
System.out.println("\t\t父线程组数量:" + group.getParent().activeGroupCount());
}
}
代码6-6运行结果:
mainThread 线程组名称:main 线程组数量:0 父线程组名称:system 父线程组数量:1
—————————————————————————————————————
group 线程组名称:new-group 线程组数量:0 父线程组名称:main 父线程组数量:1
组内线程批量停止
代码6-7
class LoopThread extends Thread {
public LoopThread(ThreadGroup group, String name) {
super(group, name);
}
@Override
public void run() {
System.out.println(getName() + "开始运行");
while (!isInterrupted()) {
}
System.out.println(getName() + "运行结束");
}
}
public class GroupInterrupt {
public static void main(String[] args) throws InterruptedException {
ThreadGroup group = new ThreadGroup("group");
for (int i = 0; i < 6; i++) {
new LoopThread(group, "线程" + i).start();
}
Thread.sleep(3000);
group.interrupt();
}
}
代码6-7运行结果:
线程0开始运行
线程3开始运行
线程2开始运行
线程1开始运行
线程5开始运行
线程4开始运行
线程2运行结束
线程5运行结束
线程3运行结束
线程1运行结束
线程4运行结束
线程0运行结束
递归与非递归取得组内对象
代码6-8
public class RecursiveGroup {
public static void main(String[] args) {
ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();
ThreadGroup groupA = new ThreadGroup("A");
ThreadGroup groupB = new ThreadGroup("B");
ThreadGroup groupC = new ThreadGroup("C");
ThreadGroup groupASon = new ThreadGroup(groupA, "A-son");
ThreadGroup groupBSon = new ThreadGroup(groupB, "B-son");
System.out.println("main线程组下共有:" + mainGroup.activeGroupCount() + "个线程");
System.out.println("main线程组下线程(包含子孙线程组):");
ThreadGroup[] recursiveGroups = new ThreadGroup[mainGroup.activeGroupCount()];
// 传入true递归出子孙线程组
mainGroup.enumerate(recursiveGroups, true);
for (ThreadGroup group : recursiveGroups) {
System.out.println(group.getName() + "线程,父线程组为:" + group.getParent().getName() + "线程组");
}
ThreadGroup groupAGrandson1 = new ThreadGroup(groupASon, "A-grandson1");
ThreadGroup groupAGrandson2 = new ThreadGroup(groupASon, "A-grandson2");
System.out.println("A线程组下共有:" + groupA.activeGroupCount() + "个线程");
System.out.println("A线程组下线程(不包含子孙线程组):");
ThreadGroup[] groups = new ThreadGroup[groupA.activeGroupCount()];
// 传入false递归出子孙线程组
groupA.enumerate(groups, false);
for (ThreadGroup group : groups) {
if (group != null) {
System.out.println(group.getName() + "线程,父线程组为:" + group.getParent().getName() + "线程组");
}
}
System.out.println("A-son线程组下共有:" + groupA.activeGroupCount() + "个线程");
System.out.println("A-son线程组下线程(不包含子孙线程组):");
groups = new ThreadGroup[groupASon.activeGroupCount()];
// 传入false递归出子孙线程组
groupASon.enumerate(groups, false);
for (ThreadGroup group : groups) {
if (group != null) {
System.out.println(group.getName() + "线程,父线程组为:" + group.getParent().getName() + "线程组");
}
}
}
}
代码6-8运行结果:
main线程组下共有:5个线程
main线程组下线程(包含子孙线程组):
A线程,父线程组为:main线程组
B线程,父线程组为:main线程组
C线程,父线程组为:main线程组
A-son线程,父线程组为:A线程组
B-son线程,父线程组为:B线程组
A线程组下共有:3个线程
A线程组下线程(不包含子孙线程组):
A-son线程,父线程组为:A线程组
A-son线程组下共有:3个线程
A-son线程组下线程(不包含子孙线程组):
A-grandson1线程,父线程组为:A-son线程组
A-grandson2线程,父线程组为:A-son线程组
使用wait()和notifyAll()使线程具有有序性
代码6-9
public class PrintABC extends Thread {
private static volatile int count = 0;
private final static Object LOCK = new Object();
private char word;
private int order;
public PrintABC(char word, int order) {
super();
this.word = word;
this.order = order;
}
@Override
public void run() {
while (true) {
synchronized (LOCK) {
try {
if (count % 3 == order) {
System.out.println(word);
LOCK.notifyAll();
count++;
} else {
LOCK.wait();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (count % 3 == 0 && count >= 10000) {
count = 0;
}
}
}
}
public static void main(String[] args) throws InterruptedException {
PrintABC threadA = new PrintABC('A', 0);
PrintABC threadB = new PrintABC('B', 1);
PrintABC threadC = new PrintABC('C', 2);
threadA.start();
threadB.start();
threadC.start();
Thread.sleep(100);
System.exit(0);
}
}
A
B
C
A
B
C
……
使用ThreaadLocal为每个线程提供单独的变量副本
一个公园有3个大门,为了统计一个时间段进公园的人数,每个大门Door类都设有Counter 对象,Counter 对象中的静态count变量会为每个大门维护一个初始值0,并且每个大门每次进来一个人则调用addPeople()方法对人数加1,而不会影响到其他大门对人数的统计
代码6-10
import java.util.Random;
class Door extends Thread {
private Counter counter;
private int count;
public Door(String name, Counter counter) {
super(name);
this.counter = counter;
}
@Override
public void run() {
while (true) {
try {
counter.addPeople();
count = counter.getCount();
System.out.println(getName() + "通过" + counter.getCount() + "个人");
Thread.sleep(ZooFlow.RANDOM.nextInt(100));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public int getCount() {
return count;
}
}
class Counter {
private static ThreadLocal<Integer> count = new ThreadLocal<Integer>() {
protected Integer initialValue() {
return 0;
};
};
public void addPeople() {
count.set(count.get() + 1);
}
public int getCount() {
return count.get();
}
}
public class ZooFlow {
public static final Random RANDOM = new Random();
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
Door first = new Door("一号门", counter);
Door second = new Door("二号门", counter);
Door third = new Door("三号门", counter);
first.start();
second.start();
third.start();
Thread.sleep(5000);
int sum = first.getCount() + second.getCount() + third.getCount();
System.out.println("统计完毕,共计:" + sum + "人");
System.exit(0);
}
}
代码6-10运行结果:
二号门通过1个人
一号门通过1个人
三号门通过1个人
三号门通过2个人
三号门通过3个人
二号门通过2个人
…………
二号门通过95个人
三号门通过91个人
一号门通过94个人
二号门通过96个人
三号门通过92个人
三号门通过93个人
统计完毕,共计:283人
线程异常处理
使用UncaughtExceptionHandler类对线程中的异常进行捕捉,进而进行有效的处理
代码6-11
import java.lang.Thread.UncaughtExceptionHandler;
class NullThread extends Thread {
public void run() {
int i = 1 / 0;
System.out.println(i);
}
}
public class ThreadException {
public static void main(String[] args) throws InterruptedException {
NullThread thread1 = new NullThread();
thread1.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("线程:" + t.getName() + "出现异常");
e.printStackTrace();
}
});
thread1.start();
Thread.sleep(100);
NullThread thread2 = new NullThread();
thread2.start();
}
}
代码6-11运行结果:
线程:Thread-0出现异常
java.lang.ArithmeticException: / by zero
at com.jerry.ch7.NullThread.run(ThreadException.java:7)
Exception in thread "Thread-1" java.lang.ArithmeticException: / by zero
at com.jerry.ch7.NullThread.run(ThreadException.java:7)
代码6-12
import java.lang.Thread.UncaughtExceptionHandler;
class NumExceptionThread extends Thread {
public void run() {
int i = 1 / 0;
System.out.println(i);
}
}
public class ThreadException {
public static void main(String[] args) throws InterruptedException {
NumExceptionThread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("线程:" + t.getName() + "出现异常");
e.printStackTrace();
}
});
NumExceptionThread thread1 = new NumExceptionThread();
thread1.start();
Thread.sleep(100);
NumExceptionThread thread2 = new NumExceptionThread();
thread2.start();
}
}
代码6-12运行结果:
线程:Thread-0出现异常
java.lang.ArithmeticException: / by zero
at com.jerry.ch7.NullThread.run(ThreadException.java:7)
线程:Thread-1出现异常
java.lang.ArithmeticException: / by zero
at com.jerry.ch7.NullThread.run(ThreadException.java:7)
线程组异常处理
代码6-13
class ThreadDemo extends Thread {
private String num;
public ThreadDemo(ThreadGroup group, String name, String num) {
super(group, name);
this.num = num;
}
@Override
public void run() {
System.out.println(getName() + "开始运行,num:" + Integer.parseInt(num));
while (true) {
}
};
}
public class GroupThreadException {
public static void main(String[] args) {
ThreadGroup group = new ThreadGroup("group");
ThreadDemo[] demos = new ThreadDemo[5];
for (int i = 0; i < 5; i++) {
demos[i] = new ThreadDemo(group, "线程" + i, i + "");
demos[i].start();
}
new ThreadDemo(group, "线程" + 6, "a").start();
}
}
代码6-13运行结果:
线程1开始运行,num:1
线程0开始运行,num:0
线程3开始运行,num:3
线程2开始运行,num:2
线程4开始运行,num:4
Exception in thread "线程6" java.lang.NumberFormatException: For input string: "a"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:492)
at java.lang.Integer.parseInt(Integer.java:527)
at com.jerry.ch7.ThreadDemo.run(GroupThreadEx.java:14)
当线程6发生异常时,其他线程并不会受到影响,如果希望当一个线程出现异常而停止,其他线程也跟着停止,需要重写java.lang.ThreadGroup中的uncaughtException()方法
代码6-14
class InterruptGroup extends ThreadGroup {
public InterruptGroup(String name) {
super(name);
}
@Override
public void uncaughtException(Thread t, Throwable e) {
super.uncaughtException(t, e);
interrupt();
}
}
class ThreadDemo extends Thread {
private String num;
public ThreadDemo(ThreadGroup group, String name, String num) {
super(group, name);
this.num = num;
}
@Override
public void run() {
System.out.println(getName() + "开始运行,num:" + Integer.parseInt(num));
while (!isInterrupted()) {
}
System.out.println(getName() + "结束运行,num:" + Integer.parseInt(num));
};
}
public class GroupThreadInterrupt {
public static void main(String[] args) throws InterruptedException {
InterruptGroup group = new InterruptGroup("group");
ThreadDemo[] demos = new ThreadDemo[5];
for (int i = 0; i < 5; i++) {
demos[i] = new ThreadDemo(group, "线程" + i, i + "");
demos[i].start();
}
Thread.sleep(100);
new ThreadDemo(group, "线程" + 6, "a").start();
}
}
代码6-14运行结果:
线程0开始运行,num:0
线程4开始运行,num:4
线程1开始运行,num:1
线程2开始运行,num:2
线程3开始运行,num:3
Exception in thread "线程6" java.lang.NumberFormatException: For input string: "a"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:492)
at java.lang.Integer.parseInt(Integer.java:527)
at com.jerrych7.ThreadDemo.run(GroupThreadInterrupt.java:27)
线程1结束运行,num:1
线程0结束运行,num:0
线程3结束运行,num:3
线程4结束运行,num:4
线程2结束运行,num:2
线程异常处理的传递
代码6-19、6-20、6-21显示了,当存在若干异常处理方式,会有哪些显示结果
代码6-15
public class ExceptionThread extends Thread {
private String num = "a";
public ExceptionThread() {
}
public ExceptionThread(ThreadGroup group, String name) {
super(group, name);
}
@Override
public void run() {
int numInt = Integer.parseInt(num);
System.out.println("线程中num:" + numInt);
}
}
代码6-16
public class TransferThreadGroup extends ThreadGroup {
public TransferThreadGroup(String name) {
super(name);
}
@Override
public void uncaughtException(Thread t, Throwable e) {
super.uncaughtException(t, e);
System.out.println("线程组的异常处理");
e.printStackTrace();
}
}
代码6-17
import java.lang.Thread.UncaughtExceptionHandler;
public class ObjectUncaughtExceptionHandler implements UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {
// TODO Auto-generated method stub
System.out.println("对象异常处理");
e.printStackTrace();
}
}
代码6-18
import java.lang.Thread.UncaughtExceptionHandler;
public class StateUncaughtExceptionHandler implements UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {
// TODO Auto-generated method stub
System.out.println("静态异常处理");
e.printStackTrace();
}
}
代码6-19
public class ThreadExceptionTransfer {
public static void main(String[] args) {
ExceptionThread thread = new ExceptionThread();
thread.setUncaughtExceptionHandler(new ObjectUncaughtExceptionHandler());
thread.setUncaughtExceptionHandler(new StateUncaughtExceptionHandler());
thread.start();
}
}
代码6-19运行结果:
静态异常处理
java.lang.NumberFormatException: For input string: "a"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:492)
at java.lang.Integer.parseInt(Integer.java:527)
at com.jerrych7.ExceptionThread.run(ExceptionThread.java:15)
代码6-20
public class ThreadExceptionTransfer {
public static void main(String[] args) {
ExceptionThread thread = new ExceptionThread();
thread.setUncaughtExceptionHandler(new StateUncaughtExceptionHandler());
thread.setUncaughtExceptionHandler(new ObjectUncaughtExceptionHandler());
thread.start();
}
}
代码6-20运行结果:
对象异常处理
java.lang.NumberFormatException: For input string: "a"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:492)
at java.lang.Integer.parseInt(Integer.java:527)
at com.jerrych7.ExceptionThread.run(ExceptionThread.java:15)
从代码6-19和6-20可以看到,当线程出现异常时会以最后一个异常处理方式作为标准
代码6-21
public class ThreadExceptionTransfer {
public static void main(String[] args) {
ExceptionThread thread = new ExceptionThread();
thread.setUncaughtExceptionHandler(new ObjectUncaughtExceptionHandler());
ExceptionThread.setDefaultUncaughtExceptionHandler(new StateUncaughtExceptionHandler());
thread.start();
}
}
代码6-21运行结果:
对象异常处理
java.lang.NumberFormatException: For input string: "a"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:492)
at java.lang.Integer.parseInt(Integer.java:527)
at com.jerrych7.ExceptionThread.run(ExceptionThread.java:15)
从以上运行结果可以看到,单独对线程设置异常处理方式,和对线程类设置异常处理类方式,当线程出现异常,会先检查自身是否已设置异常处理方式,如果没有再以线程类所设定的方式处理异常