1 拾遗增补
1.1 线程状态
名称 | 条件 |
NEW | 至今尚未启动的线程 |
RUNNABLE | 正在Java虚拟机中执行的线程 |
BLOCKED | 受阻塞并等待某个监视器锁的线程 |
WAITING | 无限期地等待另一个线程来执行某一特定操作 |
TIMED WAITING | 等待另一个线程来执行,取决于指定等待时间的操作的线程 |
TERMINATED | 已退出的线程 |
表 Java线程不同状态说明
1.2 线程组
为了方便对某些具有相同功能的线程进行管理,把线程归属到某一个线程组。
图 ThreadGroup的方法
ThreadGroup的interrupt()方法可以批量停止组内的线程。
1.3 线程与线程组的异常处理
1.3.1 线程异常处理
public class ThreadExceptionDeal {
static class MyThread extends Thread {
private String numStr;
MyThread(String numStr) {
this.numStr = numStr;
}
@Override
public void run() {
Integer integer = Integer.valueOf(numStr);
System.out.println(Thread.currentThread().getName() + "执行完成,结果是:" + integer);
}
}
public static void main(String[] args) {
//设置线程默认的异常处理
MyThread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("这是线程默认的异常处理:" + t.getName());
e.printStackTrace();
}
});
MyThread thread0 = new MyThread("21"); //正常
MyThread thread1 = new MyThread("21a"); //异常
MyThread thread2 = new MyThread("ab2"); //异常
thread2.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("这是thread2定制的异常处理");
e.printStackTrace();
}
});
thread0.start();
thread1.start();
thread2.start();
}
}
/*
运行结果
java.lang.NumberFormatException: For input string: "21a"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:580)
at java.lang.Integer.valueOf(Integer.java:766)
at com.huangmingfu.day6.article.ThreadExceptionDeal$MyThread.run(ThreadExceptionDeal.java:15)
java.lang.NumberFormatException: For input string: "ab2"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:580)
at java.lang.Integer.valueOf(Integer.java:766)
at com.huangmingfu.day6.article.ThreadExceptionDeal$MyThread.run(ThreadExceptionDeal.java:15)
这是线程默认的异常处理:Thread-1
这是thread2定制的异常处理
Thread-0执行完成,结果是:21
Process finished with exit code 0
*/
线程用静态方法设置了默认的异常处理器,也可有用实例方法定制异常处理器。 执行逻辑是,如果设置了定制的,则只执行定制异常处理器,否则执行默认的异常处理器。
1.3.2 线程组异常处理
public class ThreadGroupExceptionDeal {
static class MyThreadGroup extends ThreadGroup {
public MyThreadGroup(String name) {
super(name);
}
//重写uncaughtException方法来处理异常
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("线程组内设置的异常处理");
e.printStackTrace();
}
}
static class MyThread extends Thread {
private Integer num;
public MyThread(Integer num,ThreadGroup threadGroup,String name) {
super(threadGroup,name);
this.num = num;
}
@Override
public void run() {
System.out.println( Thread.currentThread().getName() + "执行成功,结果是" + 2 / num);
}
}
public static void main(String[] args) {
MyThreadGroup myThreadGroup = new MyThreadGroup("我的线程组");
MyThread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("这是myThread默认的异常处理");
e.printStackTrace();
}
});
MyThread myThread1 = new MyThread(0,myThreadGroup,"myThread1");
myThread1.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("thread1定制的异常处理");
e.printStackTrace();
}
});
MyThread myThread2 = new MyThread(0,myThreadGroup,"myThread2");
MyThread myThread3 = new MyThread(3,myThreadGroup,"myThread3");
myThread1.start();
myThread2.start();
myThread3.start();
}
}
/*
运行结果:
java.lang.ArithmeticException: / by zero
at com.huangmingfu.day6.article.ThreadGroupExceptionDeal$MyThread.run(ThreadGroupExceptionDeal.java:28)
java.lang.ArithmeticException: / by zero
at com.huangmingfu.day6.article.ThreadGroupExceptionDeal$MyThread.run(ThreadGroupExceptionDeal.java:28)
线程组内设置的异常处理
myThread3执行成功,结果是0
thread1定制的异常处理
Process finished with exit code 0
*/
图 ThreadGroup实现了UncaughtExceptionHandler接口
异常处理优先级为:线程定制异常处理 > 线程组重现方法异常处理 > 线程默认异常处理。
2 并发集合框架
2.1 非阻塞队列
队列里面没有数据时,返回异常或null,线程安全。
非线程安全队列 | 非阻塞队列 | 功能说明 |
HashMap | ConcurrentHashMap | |
~ | ConcurrentSkipListMap | 跳表,支持排序 |
~ | ConcurrentSkipListSet | 支持排序且不允许元素重复 |
LinkList | ConcurrentLinkedQueue | 仅支持对列头操作 |
LinkList | ConcurrentLinkedDequeue | 支持对列头和列尾双向操作 |
ArrayList | CopyOnWriteArrayList | |
HashSet | CopyOnWriteArraySet |
表 常见的非阻塞队列及其对于非安全队列
2.2 阻塞队列
阻塞队列BlockingQueue,如果其是空的,从BlockingQueue中取数据的操作将会被阻塞,进入等待状态,直到BlockingQueue中添加了元素才会被唤醒。同样,如果BlockingQueue是满的,也就是没有空余空间,试图往队列中存放元素的操作也会被阻塞,进入等待状态,直到BlockingQueue有剩余空间时才会被唤醒。
阻塞队列 | 说明 |
ArrayBlockingQueue | 有界(有固定大小)阻塞队列 |
PriorityBlockingQueue | 支持在并发情况下使用优先级队列 |
LinkedBlockingQueue | 有界的,只支持对列头操作 |
LinkedBlockingDeque | 有界的,支持对双端节点操作 |
SynchronousQueue | 经常在多个线程之间传输数据 |
DelayQueue | 延时执行任务的队列 |
LinkedTransferQueue | 与SynchronnousQueue有些类似,其还具备嗅探功能 ,可以尝试性地添加一些数据 |
表 常见的阻塞队列
2.2.1 SynchronounsQueue
每一个插入操作都必须等待另一个线程的对应移除操作完成,该线程才会继续下去,否则等待。
public class SyncQueue {
public static void main(String[] args) throws InterruptedException {
SynchronousQueue<Integer> synchronousQueue = new SynchronousQueue<>();
Thread putThread = new Thread(() -> {
Random random = new Random();
try {
for(int i = 0; i < 5; i++) {
int nextInt = random.nextInt();
System.out.println("put:" + nextInt);
synchronousQueue.put(nextInt);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread takeThread = new Thread(() -> {
try {
for(int i = 0; i < 5; i++) {
System.out.println("take:" + synchronousQueue.take());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
putThread.start();
TimeUnit.SECONDS.sleep(2);
takeThread.start();
}
}
/*
运行结果:
put:602390400
take:602390400
put:1015357793
put:2061181581
take:1015357793
take:2061181581
put:-1394104695
put:-292132860
take:-1394104695
take:-292132860
Process finished with exit code 0
*/
2.2.2 DelayQueue
是一个无界的BlockingQueue,用于放置实现了Delayed接口的对象,其中的对象只能在其到期时才能从队列中取走。这种队列是有序的。
public class DelayQueueTest {
static class Employee implements Delayed {
private String name;
private int age;
private long delaySecond;
long begin = System.currentTimeMillis();
public Employee(String name, int age, long delaySecond) {
this.name = name;
this.age = age;
this.delaySecond = delaySecond;
}
//如果该方法返回延时的时间到了,就将队列的列头中的任务取出并执行
//当返回负数,说明消息已到期,可以取出
@Override
public long getDelay(TimeUnit unit) {
long toNanos = TimeUnit.SECONDS.toMillis(delaySecond);
return toNanos + begin - System.currentTimeMillis();
}
//决定了在队列中的顺序
@Override
public int compareTo(Delayed o) {
Employee other = (Employee) o;
return other.age - this.age;
}
}
public static void main(String[] args) throws InterruptedException {
DelayQueue<Employee> queue = new DelayQueue<>();
queue.add(new Employee("小王",25,20)); //3
queue.add(new Employee("小李", 27,19)); //1
queue.add(new Employee("小张",21,12)); //4
queue.add(new Employee("小美",26,4)); //2
System.out.println("now:" + System.currentTimeMillis() / 1000);
System.out.println(queue.take().name + ":" + System.currentTimeMillis() / 1000);
System.out.println(queue.take().name + ":" + System.currentTimeMillis() / 1000);
System.out.println(queue.take().name + ":" + System.currentTimeMillis() / 1000);
System.out.println(queue.take().name + ":" + System.currentTimeMillis() / 1000);
}
}
/*
运行结果:
now:1679070117
小李:1679070136
小美:1679070136
小王:1679070137
小张:1679070137
Process finished with exit code 0
*/