VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > Java教程 >
  • 学习笔记:juc并发编程总结

1. java线程的状态

有6种,new、runnable、blocked、waiting、time_waiting、terminated。同一个时刻一个线程只可能处在其中的一个状态。
java线程状态变迁可以参考《java并发编程的艺术》中的图或者查看源码Thread.State的注释。
可以通过jstack和线程id查看运行的java线程状态

2.Daemon线程

守护线程是一种支持型线程,主要用于程序中后台调度等工作。
java虚拟机中如果没有用户线程就会退出,此时所有的守护线程都会立即终止,守护线程中的finally块不一定会执行。
在线程没有运行之前可以通过setDaemon()方法把线程设置为守护线程。

3.线程的创建方式
  • 继承Thread类:Thread类实现了Runable接口

	
 
public class MyThread extends Thread{
 
@Override
 
public void run() {
 
System.out.println(Thread.currentThread().getName()+"run");
 
}
 
}
 
class MyThreadTest{
 
public static void main(String[] args) {
 
Thread thread1 = new MyThread();
 
MyThread thread2 = new MyThread();
 
thread1.start();
 
thread2.start();
 
}
 
}
  • 实现Runnable接口

	
 
class MyThread2{
 
public static void main(String[] args) {
 
new Thread(new Runnable() {
 
@Override
 
public void run() {
 
System.out.println(Thread.currentThread().getName()+" run");
 
}
 
},"线程A").start();
 
//lambda表达式
 
new Thread(()->{
 
System.out.println(Thread.currentThread().getName()+" run");
 
},"线程B").start();
 
}
 
}
  • 实现callable接口: FutureTaskRunable接口的实现类,同时也有属性依赖callable接口,可以用来方便的创建线程。

	
 
//线程的创建方式:实现callable接口
 
public class CallableTest {
 
public static void main(String[] args) throws ExecutionException, InterruptedException {
 
//这里FutureTask构造器传入的是callable接口的匿名实现类对象
 
FutureTask<Integer> futureTask = new FutureTask<>(() -> {
 
System.out.println(Thread.currentThread().getName() + " come in callable");
 
return 1024;
 
});
 
FutureTask<Integer> futureTask2 = new FutureTask<>(() -> {
 
System.out.println(Thread.currentThread().getName() + " come in callable");
 
return 200;
 
});
 
new Thread(futureTask,"线程A").start();
 
new Thread(futureTask2,"线程B").start();
 
 
 
while (!futureTask.isDone()){
 
System.out.println("wait...");
 
}
 
System.out.println(futureTask.get());
 
System.out.println(futureTask.get());
 
System.out.println(futureTask2.get());
 
System.out.println(Thread.currentThread().getName()+" come over");
 
}
 
}
  • 线程池创建: execute()方法
4.synchronized关键字(实现线程同步)
  • synchronized锁的实现基础:java中的每一个对象都可以作为锁。 当一个线程试图访问同步代码块,它必须先得到锁,退出或者抛出异常时必须释放锁。

	
 
public class SaleTicket {
 
public static void main(String[] args) {
 
Ticket ticket = new Ticket();
 
new Thread(new Runnable() {
 
@Override
 
public void run() {
 
for (int i = 0 ; i < 30; i++) {
 
ticket.sale();
 
}
 
}
 
},"线程1").start();
 
new Thread(new Runnable() {
 
@Override
 
public void run() {
 
for (int i = 0 ; i < 30; i++) {
 
ticket.sale();
 
}
 
}
 
},"线程2").start();
 
new Thread(new Runnable() {
 
@Override
 
public void run() {
 
for (int i = 0 ; i < 30; i++) {
 
ticket.sale();
 
}
 
}
 
},"线程3").start();
 
}
 
 
 
}
 
 
 
class Ticket{
 
private int number = 30;
 
 
 
public synchronized void sale() {
 
if (number > 0) {
 
System.out.println(Thread.currentThread().getName()+"卖出了第"+number--+"票,剩下"+number+"张票");
 
}
 
}
  • synchronized(八锁问题): 反映synchronized的特点:
    • 对于同步方法,锁就是当前对象。
    • 对于静态同步方法,锁是当前类的class对象
    • 对于同步代码块,锁是synchronized括号里配置的对象。

	
 
//1.标准情况 syn通用一把锁
 
//2.加入延时 syn 锁的对象是方法的调用者 ,两个方法用的是同一把锁,谁先拿到谁先执行
 
//3.增加普通方法
 
//4.两个对象
 
//5.增加两个静态同步方法 静态方法锁的是class模板
 
//6.两个对象两个静态方法
 
//7. 一个静态同步方法 一个普通同步方法
 
//8. 两个对象 一个静态同步方法 一个普通同步方法
 
public class Test1 {
 
public static void main(String[] args) {
 
Phone phone = new Phone();
 
Phone phone1 = new Phone();
 
 
 
new Thread(()->{
 
phone.send();
 
}).start();
 
 
 
new Thread(()->{
 
phone1.call();
 
}).start();
 
 
 
new Thread(()->{
 
phone.sayHello();
 
}).start();
 
 
 
}
 
}
 
 
 
class Phone {
 
public static synchronized void send() {
 
try {
 
TimeUnit.SECONDS.sleep(4);
 
} catch (InterruptedException e) {
 
e.printStackTrace();
 
}
 
System.out.println("发短信");
 
}
 
 
 
public synchronized void call() {
 
System.out.println("打电话");
 
}
 
 
 
public void sayHello() {
 
System.out.println("Hello");
 
}
 
}
5.sleep()方法和wait()方法的区别

wait()定义在Object类中,使用在同步方法中,用于线程通信,线程调用wait方法,会释放掉锁。 sleep()定义在Thread类中,是个静态方法,用于暂停线程,线程调用sleep方法,不会释放锁 yield()定义在Thread类中,也是静态方法,用于暂停线程,让其他处于相同优先级的线程来竞争执行,始终处于runable状态 join()定义在Thread类中,是个同步方法,如果在A线程中调用了B.join()方法,A线程会取得同步方法的锁,如果B线程存活,A线程会调用wait()释放掉锁进入等待状态,直到方法完成B线程释放锁会自动唤醒A线程。这就完成了线程让步。

6.线程通信:
  • 虚假唤醒 出现虚假唤醒问题的原因:wait()方法让线程进入waiting状态,被notify()方法唤醒后会继续执行,如果使用if仅判断一次,notifyAll()会让所有之前通过if的线程执行,哪怕现在检测条件已经不满足。所以为了避免出现,需要使用while来判断。
  • 等待/通知的经典范式:
    • 获取对象的锁
    • 判断检测,不满足就调用对象的wait()方法,被通知后仍要检查条件。
    • 条件满足则执行对应的逻辑。

	
 
//虚假唤醒问题:if / while
 
public class ThreadDemo1 {
 
public static void main(String[] args) {
 
Share share = new Share();
 
new Thread(()->{
 
for (int i = 0; i < 10; i++) {
 
try {
 
share.incr();
 
} catch (InterruptedException e) {
 
e.printStackTrace();
 
}
 
}
 
},"线程1").start();
 
new Thread(()->{
 
for (int i = 0; i < 20; i++) {
 
try {
 
share.decr();
 
} catch (InterruptedException e) {
 
e.printStackTrace();
 
}
 
}
 
},"线程2").start();
 
new Thread(()->{
 
for (int i = 0; i < 10; i++) {
 
try {
 
share.incr();
 
} catch (InterruptedException e) {
 
e.printStackTrace();
 
}
 
}
 
},"线程3").start();
 
 
 
}
 
}
 
 
 
class Share{
 
private int number = 0;
 
 
 
public synchronized void incr() throws InterruptedException {
 
while (number != 0) {
 
this.wait();
 
}
 
number++;
 
System.out.println(Thread.currentThread().getName()+"执行incr,number: "+number);
 
this.notifyAll();
 
}
 
 
 
public synchronized void decr() throws InterruptedException {
 
while (number == 0) {
 
this.wait();
 
}
 
number--;
 
System.out.println(Thread.currentThread().getName()+"执行decr,number: "+number);
 
this.notifyAll();
 
}
 
}
7.lock
  • 实现多线程同步

	
 
public class LSaleTicket {
 
public static void main(String[] args) {
 
LTicket lTicket = new LTicket();
 
//lambda表达式
 
new Thread(()-> {
 
for (int i = 0; i < 30; i++) {
 
lTicket.sale();
 
}
 
},"线程1").start();
 
new Thread(()-> {
 
for (int i = 0; i < 30; i++) {
 
lTicket.sale();
 
}
 
},"线程1").start();
 
new Thread(()-> {
 
for (int i = 0; i < 30; i++) {
 
lTicket.sale();
 
}
 
},"线程1").start();
 
}
 
 
 
 
 
}
 
class LTicket{
 
private int number = 40;
 
 
 
public void sale () {
 
ReentrantLock lock = new ReentrantLock();
 
lock.lock();
 
try {
 
if (number > 0) {
 
System.out.println(Thread.currentThread().getName()+"卖出了第"+number--+"票,剩下"+number+"张票");
 
}
 
} finally {
 
lock.unlock();
 
}
 
}
 
}
  • lock实现线程通信:

	
 
public class ThreadDemo2 {
 
public static void main(String[] args) {
 
Share share = new Share();
 
new Thread(()->{
 
for (int i = 0; i < 10; i++) {
 
share.incr();
 
}
 
},"线程A").start();
 
new Thread(()->{
 
for (int i = 0; i < 10; i++) {
 
share.decr();
 
}
 
},"线程B").start();
 
new Thread(()->{
 
for (int i = 0; i < 10; i++) {
 
share.incr();
 
}
 
},"线程C").start();
 
 
 
}
 
}
 
class Share{
 
private int number = 0;
 
private Lock lock = new ReentrantLock();
 
Condition condition = lock.newCondition();
 
 
 
public void incr() {
 
lock.lock();
 
try {
 
while (number != 0) {
 
condition.await();
 
}
 
number++;
 
System.out.println(Thread.currentThread().getName()+"执行incr,number: "+number);
 
condition.signalAll();
 
} catch (InterruptedException e) {
 
e.printStackTrace();
 
} finally {
 
lock.unlock();
 
}
 
}
 
 
 
public void decr() {
 
lock.lock();
 
try {
 
while (number != 1) {
 
condition.await();
 
}
 
number--;
 
System.out.println(Thread.currentThread().getName()+"执行decr,number: "+number);
 
condition.signalAll();
 
} catch (InterruptedException e) {
 
e.printStackTrace();
 
} finally {
 
lock.unlock();
 
}
 
}
 
}
  • 实现线程间定制通信:通过改变标志位和等待/通知机制来实现

	
 
public class ThreadDemo3 {
 
public static void main(String[] args) {
 
 
 
ShareResource shareResource = new ShareResource();
 
new Thread(()->{
 
for (int i = 0; i < 10; i++) {
 
shareResource.print5(i);
 
}
 
},"线程A").start();
 
new Thread(() -> {
 
for (int i = 0; i < 10; i++) {
 
shareResource.print10(i);
 
}
 
}, "线程B").start();
 
new Thread(() -> {
 
for (int i = 0; i < 10; i++) {
 
shareResource.print15(i);
 
}
 
}, "线程C").start();
 
 
 
}
 
}
 
 
 
class ShareResource{
 
private int flag = 1;
 
 
 
private Lock lock = new ReentrantLock();
 
Condition conditionA = lock.newCondition();
 
Condition conditionB = lock.newCondition();
 
Condition conditionC = lock.newCondition();
 
 
 
public void print5(long loop) {
 
lock.lock();
 
try{
 
while (flag != 1) {
 
conditionA.await();
 
}
 
for (int i = 0; i < 5; i++) {
 
System.out.println(Thread.currentThread().getName()+"打印"+i+"轮次"+loop);
 
}
 
//改变标志位
 
flag = 2;
 
//唤醒其它线程
 
conditionB.signal();
 
} catch (InterruptedException e) {
 
e.printStackTrace();
 
} finally {
 
lock.unlock();
 
}
 
}
 
public void print10(long loop) {
 
lock.lock();
 
try{
 
while (flag != 2) {
 
conditionB.await();
 
}
 
for (int i = 0; i < 10; i++) {
 
System.out.println(Thread.currentThread().getName()+"打印"+i+"轮次"+loop);
 
}
 
//改变标志位
 
flag = 3;
 
//唤醒其它线程
 
conditionC.signal();
 
} catch (InterruptedException e) {
 
e.printStackTrace();
 
} finally {
 
lock.unlock();
 
}
 
}
 
 
 
public void print15(long loop) {
 
lock.lock();
 
try{
 
while (flag != 3) {
 
conditionC.await();
 
}
 
for (int i = 0; i < 15; i++) {
 
System.out.println(Thread.currentThread().getName()+"打印"+i+"轮次"+loop);
 
}
 
//改变标志位
 
flag = 1;
 
//唤醒其它线程
 
conditionA.signal();
 
} catch (InterruptedException e) {
 
e.printStackTrace();
 
} finally {
 
lock.unlock();
 
}
 
}
 
}
8、线程不安全的集合类
  • List 类ArrayList是线程不安全的,多个线程调用put()方法时,会抛出异常。 常用的解决方法是写时复制机制,添加集合元素时,先复制一个副本,在副本上添加元素,再让变量指针指向副本。这个过程需要持有lock锁,完成后再释放锁。

	
 
//解决list不安全
 
//1.List<Integer> list = new Vector<>();
 
//2.List<Integer> list = Collections.synchronizedList(new ArrayList<Integer>());
 
//3.List<Integer> list = new CopyOnWriteArrayList<>();
 
public class ListTest {
 
public static void main(String[] args) {
 
List<Integer> list = new CopyOnWriteArrayList<>();
 
 
 
for (int i = 0; i < 100; i++) {
 
int temp = i;
 
new Thread(()-> {
 
list.add(temp);
 
System.out.println(Thread.currentThread().getName()+list);
 
}, String.valueOf(i)).start();
 
}
 
}
 
}
  • Set

	
 
//set不安全
 
//1.Set<Integer> set = Collections.synchronizedSet(new HashSet<>());
 
//2.Set<Integer> set = new CopyOnWriteArraySet<>();
 
public class SetTest {
 
public static void main(String[] args) {
 
Set<Integer> set = new CopyOnWriteArraySet<>();
 
for (int i = 0; i < 100; i++) {
 
int temp = i;
 
new Thread(()->{
 
set.add(temp);
 
System.out.println(Thread.currentThread().getName()+set);
 
},String.valueOf(i)).start();
 
}
 
}
 
}
  • Map

	
 
//map不安全
 
//1.Map<Integer,String> map = Collections.synchronizedMap(new HashMap<>());
 
//2.Map<Integer,String> map = new ConcurrentHashMap<>();
 
public class MapTest {
 
public static void main(String[] args) {
 
Map<Integer,String> map = new ConcurrentHashMap<>();
 
for (int i = 0; i < 100; i++) {
 
int temp = i;
 
new Thread(()->{
 
map.put(temp,"hello");
 
System.out.println(Thread.currentThread().getName()+map);
 
},String.valueOf(i)).start();
 
 
 
}
 
}
 
}
9.死锁问题

出现原因

  • 竞争资源
  • 持有资源不释放

	
 
public class DeadLock {
 
public static void main(String[] args) {
 
Object a = new Object();
 
Object b = new Object();
 
new Thread(()->{
 
synchronized (a) {
 
System.out.println(Thread.currentThread().getName()+"持有锁a,想获取锁b");
 
try {
 
TimeUnit.SECONDS.sleep(2);
 
} catch (InterruptedException e) {
 
e.printStackTrace();
 
}
 
synchronized (b) {
 
System.out.println("获取到了锁b");
 
}
 
}
 
},"线程A").start();
 
new Thread(()->{
 
synchronized (b) {
 
System.out.println(Thread.currentThread().getName()+"持有锁b,想获取锁a");
 
try {
 
TimeUnit.SECONDS.sleep(2);
 
} catch (InterruptedException e) {
 
e.printStackTrace();
 
}
 
synchronized (a) {
 
System.out.println("获取到了锁a");
 
}
 
}
 
},"线程B").start();
 
}
 
}
10. 并发工具类

简单的记录一下怎么使用。

  • CountDownLatch 让一个线程或多个线程等待其它线程完成工作,如果其它线程没有完成工作,当前线程会一直处于阻塞状态,其它线程都完成工作后,才执行await()后面的程序。

	
 
public class CountDownLatch {
 
public static void main(String[] args) throws InterruptedException {
 
java.util.concurrent.CountDownLatch countDownLatch = new java.util.concurrent.CountDownLatch(6);
 
for (int i = 0; i < 6; i++) {
 
new Thread(()->{
 
System.out.println(Thread.currentThread().getName()+" 同学离开了!");
 
countDownLatch.countDown();
 
},String.valueOf(i)).start();
 
}
 
countDownLatch.await();
 
System.out.println("班长锁门了!");
 
}
 
}
  • 同步屏障CyclicBarrier 每一个线程到达一个屏障时被阻塞,直到最后一个线程到达屏障,屏障才会打开,所有被屏障拦截的线程才会继续执行。每个线程调用await()方法时表明已经到达屏障,然后当前线程被阻塞。

	
 
public class CyclicBarrierDemo {
 
public static void main(String[] args) {
 
CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{
 
System.out.println("集齐七龙珠召唤神龙!");
 
});
 
for (int i = 0; i < 7; i++) {
 
new Thread(()->{
 
System.out.println(Thread.currentThread().getName()+" 收集到龙珠!");
 
try {
 
cyclicBarrier.await();
 
} catch (InterruptedException e) {
 
e.printStackTrace();
 
} catch (BrokenBarrierException e) {
 
e.printStackTrace();
 
}
 
},String.valueOf(i)).start();
 
}
 
}
 
}
  • 信号灯 SemaPhore 控制同时访问特定资源的线程数量。 release()会动态的增加许可数量,构造器参数只是说明了一个许可证的初始值。

	
 
public class SemaPhoreDemo {
 
public static void main(String[] args) {
 
Semaphore semaphore = new Semaphore(3);
 
for (int i = 0; i < 6; i++) {
 
new Thread(()->{
 
try {
 
semaphore.acquire();
 
System.out.println(Thread.currentThread().getName()+"抢到了车位!");
 
TimeUnit.SECONDS.sleep(new Random().nextInt(5));
 
} catch (InterruptedException e) {
 
e.printStackTrace();
 
}finally {
 
semaphore.release();
 
System.out.println(Thread.currentThread().getName()+"离开了!");
 
}
 
},String.valueOf(i)).start();
 
}
 
}
 
}
11、读写锁
  • 读写锁的区别 其他锁基本是排他锁,同一时刻只允许一个线程访问,读写锁维护类一对锁,一个读锁,一个写锁,在同一时刻可以允许多个读线程访问,在写线程访问时,所有的读线程和其它写线程被阻塞
  • 锁获取 写锁获取:如果存在读锁,则不能获取,并且写锁是排他锁,只能由一个线程持有。如果允许读锁在已经获取的情况下获取写锁,那么持有读锁的线程时感觉不到写锁线程的操作的。 读锁获取:只有在当前线程获取写锁或者没有任何一个线程获得写锁的情况下,才能获取读锁。
  • 锁降级 过程:当前线程获得写锁,再获取读锁,最后释放写锁。 为什么不支持锁升级?可能有多个线程获取了读锁,在获取写锁,其它持有读锁的线程感觉不到写锁线程的操作。

	
 
public class ReadWriteLockDemo {
 
public static void main(String[] args) {
 
MyCache myCache = new MyCache();
 
//写操作
 
for (int i = 0; i < 5; i++) {
 
final int num = i;
 
new Thread(()->{
 
myCache.put(num+"",num+"");
 
},String.valueOf(i)).start();
 
}
 
//读操作
 
for (int i = 0; i < 5; i++) {
 
final int num = i;
 
new Thread(()->{
 
myCache.get(num+"");
 
},String.valueOf(i)).start();
 
}
 
}
 
}
 
 
 
class MyCache{
 
private volatile Map<Object,Object> map = new HashMap<>();
 
 
 
ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
 
 
 
public void put(Object k,Object v) {
 
//写锁
 
readWriteLock.writeLock().lock();
 
System.out.println(Thread.currentThread().getName()+" 正在写");
 
try {
 
TimeUnit.SECONDS.sleep(3);
 
map.put(k,v);
 
} catch (InterruptedException e) {
 
e.printStackTrace();
 
}finally {
 
readWriteLock.writeLock().unlock();
 
}
 
System.out.println(Thread.currentThread().getName()+" 写完了!");
 
}
 
 
 
public Object get(Object k) {
 
//读锁
 
readWriteLock.readLock().lock();
 
System.out.println(Thread.currentThread().getName()+" 正在读");
 
Object value = null;
 
try {
 
TimeUnit.SECONDS.sleep(3);
 
value = map.get(k);
 
} catch (InterruptedException e) {
 
e.printStackTrace();
 
}finally {
 
readWriteLock.readLock().unlock();
 
}
 
System.out.println(Thread.currentThread().getName()+" 读完了!");
 
return value;
 
}
 
}
12.阻塞队列
  • 定义:支持两个阻塞操作的队列 阻塞的插入方法:当队列满的的时候,队列会阻塞插入元素的线程,直到队列不满的时候 阻塞的移除方法:在队列为空的时候,队列会阻塞获取元素的线程,等待队列变为非空。
  • 常见的阻塞队列:无界的阻塞队列默认的长度是Integer.MAX_VALUE ArrayBlockingQueue 有界阻塞队列; LinkedBlockingQueue 无界阻塞队列; DelayQueue 优先级队列实现的无界阻塞队列。
  • 4中处理方式

	
 
//阻塞队列
 
public class BlockQueueDemo {
 
public static void main(String[] args) throws InterruptedException {
 
ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<Integer>(3);
 
 
 
// 第一组方法
 
System.out.println(blockingQueue.add(1));
 
System.out.println(blockingQueue.add(2));
 
System.out.println(blockingQueue.add(3));
 
System.out.println(blockingQueue.add(4));
 
 
 
System.out.println(blockingQueue.remove());
 
System.out.println(blockingQueue.remove());
 
System.out.println(blockingQueue.remove());
 
System.out.println(blockingQueue.remove());
 
 
 
// 第二组方法
 
System.out.println(blockingQueue.offer(1));
 
System.out.println(blockingQueue.offer(2));
 
System.out.println(blockingQueue.offer(3));
 
System.out.println(blockingQueue.offer(4));
 
 
 
System.out.println(blockingQueue.poll());
 
System.out.println(blockingQueue.poll());
 
System.out.println(blockingQueue.poll());
 
System.out.println(blockingQueue.poll());
 
 
 
// 第三组方法
 
blockingQueue.put(1);
 
blockingQueue.put(1);
 
blockingQueue.put(1);
 
blockingQueue.put(1);
 
 
 
blockingQueue.take();
 
blockingQueue.take();
 
blockingQueue.take();
 
blockingQueue.take();
 
 
 
//第四组方法
 
blockingQueue.offer(1,3, TimeUnit.SECONDS);
 
blockingQueue.offer(1,3, TimeUnit.SECONDS);
 
blockingQueue.offer(1,3, TimeUnit.SECONDS);
 
blockingQueue.offer(1,4, TimeUnit.SECONDS);
 
 
 
blockingQueue.poll(4,TimeUnit.SECONDS);
 
blockingQueue.poll(4,TimeUnit.SECONDS);
 
blockingQueue.poll(4,TimeUnit.SECONDS);
 
blockingQueue.poll(2,TimeUnit.SECONDS);
 
System.out.println(blockingQueue);
 
 
 
}
 
}
 
 
13.线程池

有三种常见的线程池:FixedThreadPoolSingleThreadExecutorCachedThreadPool

  • 线程池的核心参数: corePoolSize:核心线程数 maximumPoolSize:线程池最大数量 runnableTaskQueue:任务阻塞队列 keepAliveTime:线程活动保持时间 TimeUnit: 线程活动保持时间的单位 RejectedExcecutionHandler:饱和拒绝策略
  • 线程池工作流程 执行execute(),判断核心线程池满没满(是否都在执行任务),没满就创建一个工作线程;满了就下一步判断阻塞队列满没满,没满就把任务存在队列里,满了就下一步判断线程池最大线程,没满就创建一个新的工作线程,满了就下一步执行拒绝策略。 核心线程池->工作队列->线程池最大线程->拒绝策略
  • 自定义线程池:经常使用到

	
 
public class ThreadPollDemo2 {
 
public static void main(String[] args) {
 
ExecutorService threadPool = new ThreadPoolExecutor(3, 5, 2L, TimeUnit.MICROSECONDS,
 
new ArrayBlockingQueue<>(5), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
 
for (int i = 0; i < 10; i++) {
 
threadPool.execute(()->{
 
System.out.println(Thread.currentThread().getName()+"办理业务");
 
});
 
}
 
}
 
}
 
来源:https://www.cnblogs.com/echoxiatiandefeng/p/15328937.html

相关教程