Java多线程(六)

线程的状态

  • 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);
	}

}


代码6-9运行结果:

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)


从以上运行结果可以看到,单独对线程设置异常处理方式,和对线程类设置异常处理类方式,当线程出现异常,会先检查自身是否已设置异常处理方式,如果没有再以线程类所设定的方式处理异常



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值