only老K,我为自己代言
概述
What is 线程?(有点拉跨这个英语水平)
进入主题:
面试中,多线程和并发编程已经是必不可少的了,我经常看到此类问题,当时也简单了解过,什么继承Thread类,实现Runnable接口,这些都被说烂了,知道这些当然是远远不够的,于是这几天搜索相关资料恶补了一下,为了方便后期复习,在此做个总结。
继承Thread类
package com.onlyk.domexc.DomeOne;
/**
* @author only老K 我为自己代言
* @create 2020-06-21 20:02
* @blogaddress https://blog.csdn.net/weixin_44255950
*/
public class TestThread {
public static void main(String[] args) {
new MyThread().start();
System.out.println("!!!");
new Thread(new MyThread()).start();
}
}
class MyThread extends Thread{
@Override
public void run() {
String name="only老K,我为自己代言";
String[] split = name.split(",");
for (String s : split) {
System.out.println(s+"!!");
}
}
}
实现Runnable接口
package com.onlyk.domexc.DomeOne;
/**
* @author only老K 我为自己代言
* @create 2020-06-21 20:02
* @blogaddress https://blog.csdn.net/weixin_44255950
*/
public class TestThread {
public static void main(String[] args) {
// new MyThread().start();
// new Thread(new MyThread()).start();
new MyRunnable().run();
new Thread(new MyRunnable()).start();
new Thread(new MyRunnable(),"only老K").start();
}
}
class MyRunnable implements Runnable {
@Override
public void run() {
String name="only老K,我为自己代言";
String[] split = name.split(",");
for (String s : split) {
System.out.println(s+"@@@");
}
}
}
或者使用匿名内部类
package com.onlyk.domexc.DomeOne;
/**
* @author only老K 我为自己代言
* @create 2020-06-21 20:02
* @blogaddress https://blog.csdn.net/weixin_44255950
*/
public class TestThread {
public static void main(String[] args) {
// new MyThread().start();
// new Thread(new MyThread()).start();
// new MyRunnable().run();
// new Thread(new MyRunnable()).start();
// new Thread(new MyRunnable(),"only老K").start();
//使用匿名内部类
new Thread(new Runnable() {
@Override
public void run() {
String name="匿名内部类的方式,来创实现";
System.out.println(name);
}
}).start();
}
}
class MyThread extends Thread{
@Override
public void run() {
String name="only老K,我为自己代言";
String[] split = name.split(",");
for (String s : split) {
System.out.println(s+"!!");
}
}
}
class MyRunnable implements Runnable {
@Override
public void run() {
String name="only老K,我为自己代言";
String[] split = name.split(",");
for (String s : split) {
System.out.println(s+"@@@");
}
}
}
通过Lamata表达式
package com.onlyk.domexc.DomeOne;
/**
* @author only老K 我为自己代言
* @create 2020-06-21 20:02
* @blogaddress https://blog.csdn.net/weixin_44255950
*/
public class TestThread {
public static void main(String[] args) {
// new MyThread().start();
// new Thread(new MyThread()).start();
// new MyRunnable().run();
// new Thread(new MyRunnable()).start();
// new Thread(new MyRunnable(),"only老K").start();
//使用匿名内部类
// new Thread(new Runnable() {
// @Override
// public void run() {
// String name="匿名内部类的方式,来创实现";
// System.out.println(name);
// }
// }).start();
//通过Lamata表达式
new Thread(()->{
System.out.println("表达式");
}).start();
}
}
class MyThread extends Thread{
@Override
public void run() {
String name="only老K,我为自己代言";
String[] split = name.split(",");
for (String s : split) {
System.out.println(s+"!!");
}
}
}
class MyRunnable implements Runnable {
@Override
public void run() {
String name="only老K,我为自己代言";
String[] split = name.split(",");
for (String s : split) {
System.out.println(s+"@@@");
}
}
}
实现Callable
package com.onlyk.domexc.DomeOne;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
* @author only老K 我为自己代言
* @create 2020-06-22 20:45
* @blogaddress https://blog.csdn.net/weixin_44255950
*/
public class TestCallable {
public static void main(String[] args) throws Exception{
//创建执行服务
ExecutorService executorService = Executors.newFixedThreadPool(3);
//提交执行
Future submit1 = executorService.submit(new MyCallable());
Future submit2 = executorService.submit(new MyCallable());
Future submit3 = executorService.submit(new MyCallable());
//获取返回值
Object o1 = submit1.get();//这里需要抛出异常,可以进到get方法中看
Object o2 = submit2.get();
Object o3 = submit3.get();
System.out.println(o1);
System.out.println(o2);
System.out.println(o3);
//关闭服务,不然控制台会一直跑
executorService.shutdown();
}
}
class MyCallable implements Callable {
@Override
public Object call() {
for (int i = 0; i < 10 ;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}
return true;
}
}
线程状态
创建状态
所谓的创建状态,也就是我们的new Thread();
就绪状态
所谓的就绪状态,就是我们myThread.start();
运行状态
运行状态就是我们的代码执行。
阻塞状态
当线程等待(wait)、同步(synchronized)、sleep和join的时候
死亡状态
run()结束、main()结束
线程常用方法
setPriority(int new Priority)
更改线程的优先级
sleep(long millis)
让当前线程进入休眠
join()
相当于插队,插入的线程执行结束后,被插队线程继续执行。
yield()
线程礼让,暂停当前的线程,并把该线程状态转化为就绪状态
interrupt()
中断线程(不建议用)
isAlive()
判断线程是否处于存活状态
手写多线程案例
package com.onlyk.domexc.DomeOne;
/**
* @author only老K 我为自己代言
* @create 2020-06-22 20:50
* @blogaddress https://blog.csdn.net/weixin_44255950
*/
public class Dome {
public static void main(String[] args) {
DomeRunnable domeRunnable=new DomeRunnable();
new Thread(domeRunnable,"one").start();
new Thread(domeRunnable,"two").start();
new Thread(domeRunnable,"three").start();
}
}
class DomeRunnable implements Runnable{
private int num=20;
private boolean flag=true;
public void run() {
while (flag){
go();
}
}
public void go(){
if(num <=0){
flag=false;
return;
}
try {
Thread.sleep(100);
}catch (Exception e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":"+ num--);
}
}
看图片,很显然有重复的操作
正常来说我们要做到的是减到0就不会在减少了。
可以看出,出现了线程安全问题,原因是在对num变为0之前,有多个线程同时进来。
解决办法,可以通过synchronized线程同步,可以使用同步方法和同步代码块进行解决。同步方法,也就是在方法上加一个synchronized关键字。
public synchronized void run() {
while (flag){
go();
}
}
随便你怎么刷新都是一样的
同步代码块锁的是一个对象,即是需要变化的量
package com.onlyk.domexc.DomeOne;
/**
* @author only老K 我为自己代言
* @create 2020-06-22 20:50
* @blogaddress https://blog.csdn.net/weixin_44255950
*/
public class Dome {
public static void main(String[] args) {
DomeRunnable domeRunnable=new DomeRunnable();
new Thread(domeRunnable,"one").start();
new Thread(domeRunnable,"two").start();
new Thread(domeRunnable,"three").start();
}
}
class DomeRunnable implements Runnable{
MyNum myNum =new MyNum(20);
private boolean flag=true;
public synchronized void run() {
while (flag){
go();
}
}
public void go(){
if(myNum.num <=0){
flag=false;
return;
}
try {
Thread.sleep(100);
}catch (Exception e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":"+ myNum.num--);
}
}
class MyNum{
int num;
public MyNum(int num){
this.num=num;
}
}
死锁
package com.onlyk.domexc.DomeOne;
/**
* @author only老K 我为自己代言
* @create 2020-06-22 20:58
* @blogaddress https://blog.csdn.net/weixin_44255950
*/
public class DomeDIe {
public static void main(String[] args){
Only o=new Only();
King k=new King();
new Thread(new MyThread(o,k,0)).start();
new Thread(new MyThread(o,k,1)).start();
}
}
class Only{}
class King{}
class MyThread implements Runnable{
private Only o;
private King k;
private int cccc;
public MyThread(Only o,King k,int cccc){
this.o=o;
this.k=k;
this.cccc=cccc;
}
public void run() {
if(cccc == 0){
synchronized (o){
System.out.println(Thread.currentThread().getName()+"获取"+o);
try {
Thread.sleep(1000);
}catch (Exception e){
}
synchronized (k) {
System.out.println(Thread.currentThread().getName() + "获得" + k);
}
}
}else{
synchronized (k){
System.out.println(Thread.currentThread().getName()+"获取"+k);
try {
Thread.sleep(1000);
}catch (Exception e){
}
synchronized (o) {
System.out.println(Thread.currentThread().getName() + "获得" + o);
}
}
}
}
}
一直在运行,占用CPU。导致死锁
Lock锁
Lock是一个接口,而不是一个关键字,他是一个显示锁,只能锁同步代码块,不能锁方法,可以显示加锁,释放锁,可以指定唤醒某一个线程,Lock锁有一个实现类是ReentrantLock,可重入锁(递归锁),在这里说一下,所有的锁都是可重入锁,也就是如果我们获得了外面的锁之后,会自动获取里面的锁。
下面代码正常情况下会出现线程安全问题。
package com.onlyk.domexc.DomeOne;
/**
* @author only老K 我为自己代言
* @create 2020-06-22 21:03
* @blogaddress https://blog.csdn.net/weixin_44255950
*/
public class DomeLock {
public static void main(String[] args){
LockThread lockThread = new LockThread();
new Thread(lockThread).start();
new Thread(lockThread).start();
new Thread(lockThread).start();
}
}
class LockThread implements Runnable{
private int num = 100;
@Override
public void run() {
while (num > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(num --);
}
}
}
可以通过RenntrantLock进行加锁,显示锁,记得解锁。
package com.onlyk.domexc.DomeOne;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author only老K 我为自己代言
* @create 2020-06-22 21:03
* @blogaddress https://blog.csdn.net/weixin_44255950
*/
public class DomeLock {
public static void main(String[] args){
LockThread lockThread = new LockThread();
new Thread(lockThread).start();
new Thread(lockThread).start();
new Thread(lockThread).start();
}
}
class LockThread implements Runnable{
private int num = 100;
//定义一个Lock锁
ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
lock.lock();
if(num > 0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(num --);
}else{
break;
}
lock.unlock();
}
}
}
比ReentrantLock更细的锁是,ReentrantReadWriteLock,这里有一个读锁,一个写锁,
package com.onlyk.domexc.DomeOne;
import java.util.HashMap;
import java.util.Map;
/**
* @author only老K 我为自己代言
* @create 2020-06-29 21:52
* @blogaddress https://blog.csdn.net/weixin_44255950
*/
public class ReentrantLockDome {
public static void main(String[] args) {
MyReadWriteLock myReadWriteLock = new MyReadWriteLock();
for (int i = 0; i < 5; i++) {
int temp = i;
new Thread(()->{
myReadWriteLock.put(temp + "",temp + "");
},""+temp).start();
}
for (int i = 0; i < 5; i++) {
int temp = i;
new Thread(()->{
myReadWriteLock.get(temp + "");
},temp + "").start();
}
}
}
class MyReadWriteLock{
private volatile Map<String,String> map=new HashMap<String, String>();
public void put(String key,String value){
System.out.println(Thread.currentThread().getName()+"写"+key);
map.put(key,value);
System.out.println(Thread.currentThread().getName()+"写入完成");
}
public void get(String key){
System.out.println(Thread.currentThread().getName()+"读"+key);
map.get(key);
System.out.println(Thread.currentThread().getName()+"读取完成");
}
}
如果不加锁的话,在写入完成之前会被其他线程插入
我们想要的是,在写入的时候,只能是一个线程,而读取的时候,可以是多个线程
package com.onlyk.domexc.DomeOne;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* @author only老K 我为自己代言
* @create 2020-06-29 21:52
* @blogaddress https://blog.csdn.net/weixin_44255950
*/
public class ReentrantLockDome {
public static void main(String[] args) {
MyReadWriteLock myReadWriteLock = new MyReadWriteLock();
for (int i = 0; i < 5; i++) {
int temp = i;
new Thread(()->{
myReadWriteLock.put(temp + "",temp + "");
},""+temp).start();
}
for (int i = 0; i < 5; i++) {
int temp = i;
new Thread(()->{
myReadWriteLock.get(temp + "");
},temp + "").start();
}
}
}
class MyReadWriteLock{
private volatile Map<String,String> map = new HashMap<>();
ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
public void put(String key,String value) {
readWriteLock.writeLock().lock();
System.out.println(Thread.currentThread().getName() + "写入" + key);
map.put(key,value);
System.out.println(Thread.currentThread().getName() + "写入完成");
readWriteLock.writeLock().unlock();
}
public void get(String key) {
readWriteLock.readLock().lock();
System.out.println(Thread.currentThread().getName() + "读取" + key);
map.get(key);
System.out.println(Thread.currentThread().getName() + "读取完成");
readWriteLock.readLock().unlock();
}
}
synchronized和Lock的区别
- synchronized是关键字,Lock是类
- synchronized无法获取锁的状态,Lock可以
- synchronized会自动释放锁,Lock需要手动
- synchronized没有Lock锁灵活(Lock锁可以自己定制)
只说理论是不行的,下面说几个ReentrantLock的场景
ReentrantLock默认是非公平锁,但它可以设置公平锁,也就是谁先来的谁先获得锁new ReentrantLock(true)。
ReentrantLock可以响应中断,也就是当两个线程发生死锁的时候,你把A线程中断了,B线程可以正常运行。
ReentrantLock可以通过tryLock()实现限时等待,这样可以解决死锁问题。
synchronized
synchronized在JDK1.6进行了锁的优化,也就是当一个线程多次访问一个同步代码块的时候,此时会记录该线程的threadId也就是,当你再来访问的时候,我就只需判断threadId就行了,效率高,这属于偏向锁。
当有多个线程来的时候,那么这个锁就会升级为轻量级锁,也就是通过CAS,来进行尝试获取锁,是一种自旋锁的状态。如果在短时间内可以获得锁,不会堵塞,而且节约了CUP上下文切换的时间。
如果长时间没有获取到锁,会消耗CUP的资源,因为在那一直死循环,经过一个时间段后会升级为重量级锁,会发生阻塞。其中锁升级是不可逆的。
生产者消费者问题
这是一个经典的线程通信问题,也就是不同线程之间有联系,生产者生产的东西放到缓冲区,如果缓冲区满了,生产者进入堵塞,缓冲区空了,消费者堵塞。
常用的方法有wait(),notify(),notifyAll()
package com.onlyk.domexc.Seven8;
/**
* @author only老K 我为自己代言
* @create 2020-07-08 12:26
* @blogaddress https://blog.csdn.net/weixin_44255950
*/
public class dome {
public static void main(String[] args) {
Buffer buffer=new Buffer();
new Thread(()->{
for (int i = 0; i < 100; i++) {
System.out.println("生产者生产了" + i);
buffer.put();
}
},"生产者").start();
new Thread(()->{
for (int i = 0; i < 100; i++) {
System.out.println("消费者消费了" + i);
buffer.get();
}
},"消费者").start();
}
}
//缓冲区
class Buffer{
private int len=0;
public synchronized void put (){
if (len < 10){
len++;
}else{
try {
wait();
}catch (Exception e){
}
}
notifyAll();
}
public synchronized void get() {
if (len > 0) {
len --;
} else {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
notifyAll();
}
}
其中这里引入了Condition,他可以指定唤醒某个线程,这里我们演示三个线程ABC。
package com.onlyk.domeone.Thread;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Main {
public static void main(String[] args) {
Buffer buffer = new Buffer();
new Thread(()->{
for (int i = 0; i < 10; i++) {
buffer.a();
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
buffer.b();
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
buffer.c();
}
},"C").start();
}
}
// 缓冲区
class Buffer {
private int flag = 1;// 1执行A,2执行B,3执行C
Lock lock = new ReentrantLock();
Condition condition1 = lock.newCondition();// 该对象可以设置一些条件
Condition condition2 = lock.newCondition();// 该对象可以设置一些条件
Condition condition3 = lock.newCondition();// 该对象可以设置一些条件
public void a() {
lock.lock();
try {
while (flag != 1) {
condition1.await();
}
System.out.println("A");
flag = 2;
condition2.signal();// 指定唤醒B
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void b() {
lock.lock();
try {
while (flag != 2) {
condition2.await();
}
System.out.println("B");
flag = 3;
condition3.signal();// 指定唤醒C
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void c() {
lock.lock();
try {
while (flag != 3) {
condition3.await();
}
System.out.println("C");
flag = 1;
condition1.signal();// 指定唤醒A
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
八锁问题
一锁
package com.onlyk.domexc.Seven8;
import java.util.concurrent.TimeUnit;
/**
* @author only老K 我为自己代言
* @create 2020-07-08 7:49
* @blogaddress https://blog.csdn.net/weixin_44255950
*/
public class dome1 {
public static void main(String[] args) {
Man man=new Man();
new Thread(()->{
man.go();
}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
man.in();
}).start();
}
}
class Man{
public synchronized void go(){
System.out.println("出去");
}
public synchronized void in(){
System.out.println("进来");
}
}
先输出出去
,不要理解为是先调用了go()
,而是因为上面线程先获得了锁。
二锁
class Man{
public synchronized void go(){
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("出去");
}
public synchronized void in(){
System.out.println("进来");
}
}
结果还是一样的啊。这里的synchronized锁的对象是调用者,这两个方法用的是同一把锁,谁先拿到,谁先执行
三锁
class Man{
public synchronized void go(){
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("出去");
}
public void in(){
System.out.println("进来");
}
}
这里in()
方法是没有使用synchronized锁的了,等于就是先输出in()
因为他不去获取锁资源,所以直接输出了
四锁
package com.onlyk.domexc.Seven8;
import java.util.concurrent.TimeUnit;
/**
* @author only老K 我为自己代言
* @create 2020-07-08 7:49
* @blogaddress https://blog.csdn.net/weixin_44255950
*/
public class dome1 {
public static void main(String[] args) {
Man man=new Man();
Man king=new Man();
new Thread(()->{
man.go();
}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
king.in();
}).start();
}
}
class Man{
public synchronized void go(){
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("出去");
}
public synchronized void in(){
System.out.println("进来");
}
}
这里用两个Man对象,分别调用go和in方法,会先执行哪个?因为这里的锁锁的是对象,而他们不是同一个对象,所以资源不受影响。所以先执行in()
五锁
package com.onlyk.domexc.Seven8;
import java.util.concurrent.TimeUnit;
/**
* @author only老K 我为自己代言
* @create 2020-07-08 7:49
* @blogaddress https://blog.csdn.net/weixin_44255950
*/
public class dome1 {
public static void main(String[] args) {
Man man=new Man();
new Thread(()->{
man.go();
}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
man.in();
}).start();
}
}
class Man{
public static synchronized void go(){
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("出去");
}
public static synchronized void in(){
System.out.println("进来");
}
}
这里是通过一个对象,去调用静态的同步方法。这里锁的是Class对象(只有一个)。
六锁
package com.onlyk.domexc.Seven8;
import java.util.concurrent.TimeUnit;
/**
* @author only老K 我为自己代言
* @create 2020-07-08 7:49
* @blogaddress https://blog.csdn.net/weixin_44255950
*/
public class dome1 {
public static void main(String[] args) {
Man man=new Man();
Man king=new Man();
new Thread(()->{
man.go();
}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
king.in();
}).start();
}
}
class Man{
public static synchronized void go(){
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("出去");
}
public static synchronized void in(){
System.out.println("进来");
}
}
这里是通过两个对象去调用go和in,结果是什么呢,答案还是先执行go,因为锁的是Class对象,所以不管是man还是king,都是属于Phone的Class对象。
七锁
package com.onlyk.domexc.Seven8;
import java.util.concurrent.TimeUnit;
/**
* @author only老K 我为自己代言
* @create 2020-07-08 7:49
* @blogaddress https://blog.csdn.net/weixin_44255950
*/
public class dome1 {
public static void main(String[] args) {
Man man=new Man();
new Thread(()->{
man.go();
}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
man.in();
}).start();
}
}
class Man{
public static synchronized void go(){
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("出去");
}
public synchronized void in(){
System.out.println("进来");
}
}
一个是静态同步方法,一个是普通同步方法,用一个对象对调用。静态同步方法锁的是Class对象,而普通同步方法锁的是调用者,锁的不是同一个东西。
八锁
package com.onlyk.domexc.Seven8;
import java.util.concurrent.TimeUnit;
/**
* @author only老K 我为自己代言
* @create 2020-07-08 7:49
* @blogaddress https://blog.csdn.net/weixin_44255950
*/
public class dome1 {
public static void main(String[] args) {
Man man=new Man();
Man king=new Man();
new Thread(()->{
man.go();
}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
king.in();
}).start();
}
}
class Man{
public static synchronized void go(){
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("出去");
}
public synchronized void in(){
System.out.println("进来");
}
}
这里用两个对象去调用静态同步方法go和普通同步方法in,会先输出哪个,答案是in,因为go锁的是Class,而in锁的是调用者,不是同一个一个东西
线程池
package com.onlyk.domexc.Seven8;
import java.security.Policy;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author only老K 我为自己代言
* @create 2020-07-08 9:29
* @blogaddress https://blog.csdn.net/weixin_44255950
*/
public class dome2 {
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(5);// 创建固定个数线程
// ExecutorService pool1 = Executors.newCachedThreadPool();// 创建动态线程(自适应大小)
// ExecutorService pool2 = Executors.newSingleThreadExecutor();// 创建单个线程
pool.execute(new PoolThread());
pool.execute(new PoolThread());
pool.execute(new PoolThread());
// 关闭连接 不关闭连接会一直占用CPU
pool.shutdown();
}
}
class PoolThread implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
但是按照阿里规范的话就是不推荐我们使用这种
对于ThreadPoolExecutor的学习,就从七大参数,四种拒绝策略
int corePoolSize// 核心线程池大小
int maximumPoolSize// 最大核心线程池大小
long keepAliveTime// 超时存活时间
TimeUnit unit// 超时单位
BlockingQueue<Runnable> workQueue// 阻塞队列
ThreadFactory threadFactory// 线程工厂,用于创建线程
RejectedExecutionHandler handler// 拒绝策略
四种拒绝策略:
AbortPolicy());// 银行满了还有人进来,不处理,抛出异常(默认)
CallerRunsPolicy();// 银行满了,不处理,哪里来的去哪里,一般抛给main线程
DiscardPolicy();// 银行满了,把该线程丢掉,不抛异常
DiscardOldestPolicy();// 银行满了,会和先来的线程竞争,不抛异常
package com.onlyk.domexc.Seven8;
import java.util.concurrent.*;
/**
* @author only老K 我为自己代言
* @create 2020-07-08 12:14
* @blogaddress https://blog.csdn.net/weixin_44255950
*/
public class dome3 {
public static void main(String[] args){
/**
* 用一个银行的例子进行讲解这七大参数
*/
ExecutorService threadPool = new ThreadPoolExecutor(
2,// 两个常开营业窗口
5,// 五个窗口,其中三个应急用
3,// 超时存货时间
TimeUnit.SECONDS,// 超时时间单位
new LinkedBlockingDeque<>(3),// 银行候客区大小
Executors.defaultThreadFactory(),// 默认线程池工厂
new ThreadPoolExecutor.AbortPolicy());// 银行满了还有人进来,不处理,抛出异常(默认)
// new ThreadPoolExecutor.CallerRunsPolicy();// 银行满了,不处理,哪里来的去哪里,一般抛给main线程
// new ThreadPoolExecutor.DiscardPolicy();// 银行满了,把该线程丢掉,不抛异常
// new ThreadPoolExecutor.DiscardOldestPolicy();// 银行满了,会和先来的线程竞争,不抛异常
for (int i = 0; i < 8; i++) {
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName());
});
}
// 关闭连接
threadPool.shutdown();
}
}
end…