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{ |
|
|
|
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() { |
|
|
|
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接口:
FutureTask
是Runable
接口的实现类,同时也有属性依赖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() { |
|
|
|
public void run() { |
|
for (int i = 0 ; i < 30; i++) { |
|
ticket.sale(); |
|
} |
|
} |
|
},"线程1").start(); |
|
new Thread(new Runnable() { |
|
|
|
public void run() { |
|
for (int i = 0 ; i < 30; i++) { |
|
ticket.sale(); |
|
} |
|
} |
|
},"线程2").start(); |
|
new Thread(new Runnable() { |
|
|
|
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.线程池
有三种常见的线程池:FixedThreadPool
、SingleThreadExecutor
、CachedThreadPool
-
线程池的核心参数:
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()+"办理业务"); |
|
}); |
|
} |
|
} |
|
} |