多线程实现方式1
public class ThreadDemo {
public static void main(String[] args) {
//获取当前线程名城
System.out.println(Thread.currentThread().getName());//main
MyThread myThread = new MyThread();
//run()仅仅封装线程执行的代码
//start()首先启动线程 ,在由JVM调用run方法
//myThread.start();
//myThread.start();
//java.lang.IllegalThreadStateException
//start是启动线程 启动俩次会报错
//所以创建俩个线程
MyThread myThread1 = new MyThread();
myThread.setName("张三");
myThread1.setName("李四");
myThread.start();
myThread1.start();
}
}
class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i <1000 ; i++) {
System.out.println(getName()+" "+i);
}
}
}
线程调度
分时调度
抢占式调度(默认)
线程优先级
setPriority () 给线程设置优先级 默认值为5 值得范围1-10
1)、线程休眠 Thread.sleep(int)
2)、线程礼让 Thread.yield() 让其他线程走 在一定程度让线程执行更和谐
3)、线程守护(后台线程) public final void setDemo()
- 、线程加入 public final void join() 等待线程终止
线程状态
多线程实现方式2
实现Runnable
重写run方法
创建MyRunnable对象
创建Thread对象 把MyRunnable对象作为参数传递
public class ThreadDemo {
public static void main(String[] args) {
MyThread myThread = new MyThread();
Thread thread1 = new Thread(myThread,"张三");
Thread thread2 = new Thread(myThread,"李四");
thread1.start();
thread2.start();
}
}
class MyThread implements Runnable{
@Override
public void run() {
for (int i = 0; i <1000 ; i++) {
System.out.println(Thread.currentThread().getName()+i);
}
}
}
有了第一种为什么还要第二种呢? 第一种是继承 如果一个类已经有父类他就不能继承Thread 有局限性
模拟卖票
使用继承Thread的方式 我们发现每个人都卖了100张 因为创建了三个MyThread对象 那就加static关键字
但是我们不想加关键字怎么办?使用实现Runnable接口的方式 ,这样就只会创建一个对象,多个线程共享这一个变量 运行发现 还是不对,某张票可能卖了多次 而且还出现了负数票 ,这是因为A线程卖第100张票的时候还没有减票数 B也进来卖第100张票,负数票同理 A卖第1张的时候还没减票数的时候 B也进入方法 C也进入方法
A 卖第1张票 ticket =0 B卖0张票 ticket =-1 C卖-1 ticket=-2
这就叫线程安全
Synchronized
解决线程安全 :既然多线程有多条语句操作共享数据 那我们就把多条语句包起来 使多条语句变成原子性的
synchronized (o):对象锁解释:一个对象对应一把锁 A线程进入会把该方法后会把锁的钥匙带走 B来了之后 没有钥匙 就会等待 如果每个线程进来都new一个对象锁 new的时候会出现钥匙 所以达不到锁的目的
public class ThreadDemo {
public static void main(String[] args) {
MyThread myThread = new MyThread();
Thread thread1 = new Thread(myThread,"张三");
Thread thread2 = new Thread(myThread,"李四");
Thread thread3 = new Thread(myThread,"王五");
thread1.start();
thread2.start();
thread3.start();
}
}
class MyThread implements Runnable{
private int ticket=100;
private Object o = new Object();
@Override
public void run() {
while (true) {
synchronized (o) { //对象是关键
if(ticket>0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "卖了第" + ticket + "张票");
ticket--;
}
else break;;
}
}
}
}
如果方法一进去就是run 那就可以把synchaonized加在方法上 对象默认是this
以前学的线程安全类
静态方法的锁是当前类class对象
创建线程安全的集合 Connections.synchronizedList(new HashMap()) 返回一个线程安全的hashmap集合
Lock
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ThreadDemo {
public static void main(String[] args) {
MyThread myThread = new MyThread();
Thread thread1 = new Thread(myThread,"张三");
Thread thread2 = new Thread(myThread,"李四");
Thread thread3 = new Thread(myThread,"王五");
thread1.start();
thread2.start();
thread3.start();
}
}
class MyThread implements Runnable{
private int ticket=1000;
private Object o = new Object();
Lock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
lock.lock();
try {
if(ticket>0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "卖了第" + ticket + "张票");
ticket--;
}
else break;;
}
finally {
lock.unlock();
}
}
}
}
线程死锁
public class ThreadDemo {
public static void main(String[] args) {
DieLock dieLock = new DieLock(true);
DieLock dieLock1 = new DieLock(false);
dieLock.start();
dieLock1.start();
}
}
class MyLock{
public static Object oA = new Object();
public static Object ob = new Object();
}
class DieLock extends Thread{
private boolean flag;
public DieLock(boolean flag){
this.flag=flag;
}
@Override
public void run() {
if(flag){
synchronized (MyLock.oA){
System.out.println("ifoA");
synchronized (MyLock.ob){
System.out.println("ifob");
}
}
}
else {
synchronized (MyLock.ob){
System.out.println("elseob");
synchronized (MyLock.oA){
System.out.println("elseoA");
}
}
}
}
}
线程死锁有什么解决办法呢? 线程通信
线程通信
生产者与消费者
有下面几个问题
1 生产者生产了一半 消费者抢到资源 (消费者和生产者加锁 必须是同一个锁对象)
2 消费者先抢到资源 还没有生产任何东西
3 生产者一直生产 消费者抢不到怎么办
4生产者生产了一个 消费者得到N个怎么办
等待唤醒机制
Object类提供了俩个方法 wait()等待 和notify()唤醒
/*
资源类 Studnet
生产者 GetStudnet
消费者 SetStudnet
测试类 ThreadDemo
*/
public class ThreadDemo{
public static void main(String[] args) {
Student s = new Student();
SetStudent setStudent = new SetStudent(s);
GetStudent getStudent = new GetStudent(s);
Thread t1 = new Thread(setStudent,"生产者");
Thread t2 = new Thread(getStudent,"消费者");
t2.start();
t1.start();
}
}
class Student{
String name;
int age;
boolean flag;//如果是true就代表有数据
}
class SetStudent implements Runnable{
Student s;
int x =0;
public SetStudent(Student s){
this.s=s;
}
@Override
public void run() {
while (true) {
synchronized (s){
if(s.flag){
try {
s.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(x%2==0) {
s.name = "张三";
s.age = 18;
}
else {
s.name="王五";
s.age=28;
}
x++;
s.flag=true;
s.notify();
}
}
}
}
class GetStudent implements Runnable{
Student s;
public GetStudent(Student s){
this.s=s;
}
@Override
public void run() {
while (true) {
synchronized (s){
if(!s.flag){
try {
s.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(s.age + "---" + s.name);
s.flag=false;
s.notify();
}
}
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O4X2aRZ1-1586532994642)(C:\Users\李嘉伟\AppData\Roaming\Typora\typora-user-images\image-20200407222926519.png)]
线程组
/*
资源类 Studnet
生产者 GetStudnet
消费者 SetStudnet
测试类 ThreadDemo
*/
public class ThreadDemo{
public static void main(String[] args) {
MyThread myThread = new MyThread();
ThreadGroup threadGroup = new ThreadGroup("新的线程组");
Thread t1 = new Thread(threadGroup,myThread,"生产者");
Thread t2 = new Thread(threadGroup,myThread,"消费者");
System.out.println(t1.getThreadGroup().getName());
System.out.println(t2.getThreadGroup().getName());
t2.start();
t1.start();
}
}
class MyThread implements Runnable{
@Override
public void run() {
}
}
组的方便之处
通过组设置优先级和后台线程 等等 一次行操作多个线程 就是线程组的功能
多线程实现方式3
实现Callable接口
这个方式的特点就是有返回值
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class Demo{
public static void main(String[] args) throws ExecutionException, InterruptedException {
//Future实现了Runable接口
FutureTask futureTask = new FutureTask(new MyThread());
Thread t = new Thread(futureTask);
t.start();
Object o = futureTask.get();
System.out.println(o);
}
}
class MyThread implements Callable<Integer>{
@Override
public Integer call() throws Exception {
//进入方法
System.out.println("income");
//返回值
return 1024;
}
}
注意:不管有多少new Thread(futureTask); 都只会启动一个线程
Synchronized和lock锁的区别
1、Synchronized是关键字 lock是接口
2、Synchronized 无法判断锁的状态 LOCK可以获得锁
3、Synchronized 会自动释放锁 LOCK必须手动释放锁 否则死锁
4、
求和案例
import java.util.concurrent.*;
public class ThreadDemo{
public static void main(String[] args) throws ExecutionException, InterruptedException {
//创建线程池 并指定线程数量
ExecutorService service = Executors.newFixedThreadPool(2);
//往线程池里放线程
Future<Integer> f1 = service.submit(new MyThread(100));
Future<Integer> f2 = service.submit(new MyThread(200));
System.out.println(f1.get());
System.out.println(f2.get());
service.shutdown();
}
}
class MyThread implements Callable<Integer> {
Integer number;
Integer sum=0;
public MyThread(Integer number){
this.number=number;
}
@Override
public Integer call() throws Exception {
for (int i = 0; i <= number; i++) {
sum += i;
}
return sum;
}
}
消费者生产者口诀
所有业务写在lock内
加锁 干活 修改资源 释放锁
1、 JUC
1.1 进程/并发
1.2 并发/并行
2、三个包
- java.util.concurrent
- java.util.concurrent.atomic
- java.util.concurrent.locks
可重入锁:重复利用的锁
wait和sleep的区别
wait必须在同步代码块中使用 waite后会释放锁
sleep可以在任意地方使用 sleep后不会释放锁
匿名内部类实现多线程
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ThreadDemo{
public static void main(String[] args){
Resources ticket = new Resources();
new Thread(new Runnable() {
@Override
public void run() {
while (ticket.ticket>0) {
ticket.slae();
}
}
},"张三").start();
new Thread(new Runnable() {
@Override
public void run() {
while (ticket.ticket>0) {
ticket.slae();
}
}
},"李四").start();
new Thread(new Runnable() {
@Override
public void run() {
while (ticket.ticket>0) {
ticket.slae();
}
}
},"王五").start();
}
}
//资源类
class Resources{
int ticket=300;
Lock lock = new ReentrantLock();
public void slae(){
lock.lock();
try{
if (ticket>0){
System.out.println(Thread.currentThread().getName()+ticket--);
}
}catch(Exception e){
e.printStackTrace();
}finally{
lock.unlock();
}
}
}
lambda表达式
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ThreadDemo{
public static void main(String[] args){
Resources ticket = new Resources();
new Thread(()->{ while (ticket.ticket>0) { ticket.slae(); }},"张三").start();
new Thread(()->{ while (ticket.ticket>0) { ticket.slae(); }},"李四").start();
new Thread(()->{ while (ticket.ticket>0) { ticket.slae(); }},"王五").start();
}
}
//资源类
class Resources{
int ticket=300;
Lock lock = new ReentrantLock();
public void slae(){
lock.lock();
try{
if (ticket>0){
System.out.println(Thread.currentThread().getName()+ticket--);
}
}catch(Exception e){
e.printStackTrace();
}finally{
lock.unlock();
}
}
}
3、集合类线程不安全
1)、List
new Arraylist: new了一个容量是10的数组
扩容扩到多少 ?扩原来的一半+1 15 Arrays.copyof() 搬家 在扩22 取整
hasmap 初始容量16 阈值0.75 扩容一倍
arrayList线程不安全
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class ThreadDemo{
public static void main(String[] args) {
List<String> list = new ArrayList();
for (int i = 0; i <30 ; i++) {
new Thread(()->
{ list.add(UUID.randomUUID().toString().substring(0,8));
System.out.println(Thread.currentThread().getName()+"-"+list);
},String.valueOf(i)).start();
}
}
}
1)、故障现象
java.util.ConcurrentModificationException
2)、导致原因
在很多容器(比如ArrayList)中,都有一个变量记录你从结构上修改此容器的次数,叫做modCount,比如你调用add方法向容器里面增加了一个元素,或者你删除了其中的某个元素,这个值都会增加1.在对集合进行迭代的时候,这个值不能被改变,否则抛出
ConcurrentModificationException。简单地说就是你在遍历的时候,你自己不会去改变这个值,但是你在遍历的过程中发现这个值被改变了,那只有一种解释,其他人修改了集合导致这个值改变了。
3)、解决办法
1 : List list = new Vector<>();
2:List list = new collections.synchronized(new ArrayList)
3:List list = new CopyOnWriteArrayList();
4)、优化建议
CopyOnWriteArrayList
写的时候复制一份之前的ArrayList 加锁 其他线程读之前的ArrayList 写完之后 删除之前的ArrayList
2、Set
Set线程不安全 HashSet底层数据结构HashMap 使用CopyOnWriteArraySet() 创造线程安全的set
set底层是hashmap set丢进去的是 key value是源码定义的一个Object对象
3.map
map 线程不安全 线程安全 :new ConcurrentHashMap() map没有写时复制
map底层1.7使用数组加链表 当发生hash碰撞之后 会形成链表 1.8之后链表长度>8的时候会变成红黑树 数组扩容有个阈值 0.75 数组长度达到0.75会发生扩容 扩之前的一半
八个线程问题
public class ThreadDemo{
public static void main(String[] args) throws InterruptedException {
Resources res = new Resources();
Resources res1 = new Resources();
new Thread(new Runnable() {
@Override
public void run() {
res.senmessage();
}
},"A").start();
Thread.sleep(100);//停一下 保证线程A先执行
Resources res1 = new Resources();
new Thread(new Runnable() {
@Override
public void run() {
res.senemail();
}
},"B").start();
}
}
/*资源类
*/
class Resources {
public synchronized void senmessage(){
System.out.println("发短信");
}
public synchronized void senemail(){
System.out.println("发邮件");
}
}
1标准访问先发短信还是邮件 先发短信 ? :发短信 A线程进入资源类之后 锁住了资源类的所有synchronized方法
2发邮件中暂停4秒 先发邮件还是短信 ? :发短信 A线程进入资源类之后 锁住了资源类的所有synchronized方法
3新增普通sayhello方法 不加synchronized 先发短信还是sayhello?: sayhello 因为没上锁
4 新增手机 先打印什么:? 发邮件 因为不是同一个锁 A线程用 res锁 B线程用res1锁
5加static 同一个手机 先打印什么? 先打印短信 因为同一个类锁
6加static 俩个手机 先打印什么 ? 先打印短信 因为同一个类锁
7 一个静态同步 一个普通同步方法 先打印什么? 先打印 邮件 因为一个是类锁 一个是 this锁
8一个静态同步 一个普通同步方法 俩个手机 先打印什么? 发邮件 因为一个类锁 一个 this锁
还是卖票问题
public class Demo {
public static void main(String[] args) {
Ticket ticket = new Ticket();
new Thread(new Runnable() {
@Override
public void run() {
try {
for (int i = 0; i <10 ; i++) {
ticket.increment();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "A").start();
new Thread(new Runnable() {
@Override
public void run() {
try {
for (int i = 0; i <10; i++) {
ticket.decrement();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "B").start();
}
}
class Ticket{
int number=0;
public synchronized void increment() throws InterruptedException {
if(number!=0){
this.wait();
}
number++;
System.out.println("生产了1张票");
this.notifyAll();
}
public synchronized void decrement() throws InterruptedException {
if (number==0){
this.wait();
}
number--;
System.out.println("取走一张票");
this.notifyAll();
}
}
1)、虚假唤醒
在上面的卖票代码中 如果在加入一个生产者线程和一个消费者线程 就会出现生产多张票和取走多张票的错误
因为?线程被唤醒的时候 他已经进入了判断语句 不管票数是多少他就会往下执行,API规定判断应该使用while不能使用if否则出现虚假唤醒,whileyou俩个作用 一个循环 一个被唤醒后在判断
为什么俩个线程不会出问题?
2)、Lock锁卖票
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Demo {
public static void main(String[] args) {
Resource resource = new Resource();
new Thread(()->{
for (int i = 0; i <500 ; i++) {
resource.sale();
}
},"张三").start();
new Thread(()->{
for (int i = 0; i <500 ; i++) {
resource.sale();
}
},"李四").start();
new Thread(()->{
for (int i = 0; i <500 ; i++) {
resource.sale();
}
},"王五").start();
}
}
class Resource {
private int ticket=300;
Lock lock = new ReentrantLock();
public void sale() {
lock.lock();
try{
if(ticket>0) {
System.out.println(Thread.currentThread().getName() + "卖了第" + ticket + "张票");
ticket--;
}
}catch(Exception e){
e.printStackTrace();
}finally{
lock.unlock();
}
}
}
使用Lock锁之后不能再使用synchronized 配套的wait和notify ,notifyAll
Lock锁 应该使用 lock.newCondition 获得 Condition 对象 使用该对象的await 和singal singalAll 替代
3)、精确唤醒线程
在synchronized中notify无法指定唤醒哪一个线程 下面使用Lock唤醒
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/*
A线程 打印5次 B线程打印10次 C线程打印15次 依次执行
*/
public class Demo {
public static void main(String[] args) {
Resource r = new Resource();
new Thread(() -> {
for (int i = 0; i <10 ; i++)
r.print5();
},"A").start();
new Thread(() -> {
for (int i = 0; i <10 ; i++)
r.print10();
},"B").start();
new Thread(() -> {
for (int i = 0; i <10 ; i++)
r.print15();
},"C").start();
}
}
class Resource {
private int num = 1; //标志位 1A打印 2B打印 3C打印
private Lock lock = new ReentrantLock();
private Condition c1 = lock.newCondition();
private Condition c2 = lock.newCondition();
private Condition c3 = lock.newCondition();
public void print5() {
lock.lock();
try {
while (num!=1){
c1.await();
}
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + "--" + i);
}
num=2;
c2.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void print10() {
lock.lock();
try {
while (num!=2){
c2.await();
}
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "--" + i);
}
num=3;
c3.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void print15() {
lock.lock();
try {
while (num!=3){
c3.await();
}
for (int i = 0; i < 15; i++) {
System.out.println(Thread.currentThread().getName() + "--" + i);
}
num=1;
c1.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
countdownlatch
这个类可以指定哪一个线程 在什么时候执行
N可线程执行完毕 这个线程才可以执行 这些都可以设置
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class Demo{
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(6);//6为有6个线程结束之后才怎么怎么样
for (int i = 0; i <6 ; i++) {
new Thread(new Runnable(){
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"走出教室");
countDownLatch.countDown();//执行完减一个
}
},String.valueOf(i)).start();
}
//只有减为0的时候 才会执行否则等待唤醒
countDownLatch.await();
System.out.println("Main结束");
}
}
CyclicBarrier
和countdownlatch相反 这个类是
semaphore
适用于多个线程抢多个资源
抢到资源 资源数减一 放弃资源 资源数+1
import java.util.concurrent.*;
public class Demo{
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(3);//指定3个资源
for (int i = 0; i <6 ; i++) {
new Thread(()->{
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName()+"\t抢到了车位");
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName()+"\t离开了车位");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
semaphore.release();//离开车位 资源车位数+1
}
},String.valueOf(i)).start();
}
}
}
读写锁ReadWriteLock
为什么又出来了一个锁?Lock锁 把读和写操作都锁了 但是读的时候没必要锁
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
public class Demo{
public static void main(String[] args) {
Book book = new Book();
for (int i = 0; i <5 ; i++) {
String a = String.valueOf(i);
new Thread(()->{
book.put(a,a);
},String.valueOf(i)).start();
}
for (int i = 0; i <5 ; i++) {
String b = String.valueOf(i);
new Thread(()->{
book.get(b);
},String.valueOf(i)).start();
}
}
}
class Book{
private Map<String,String> map = new HashMap<>();
public void put(String key,String value){
System.out.println(Thread.currentThread().getName()+"\t正在写入");
map.put(key, value);
System.out.println(Thread.currentThread().getName()+"\t写入完成");
}
public void get(String key){
System.out.println(Thread.currentThread().getName()+"\t正在读"+key);
String value = map.get(key);
System.out.println(Thread.currentThread().getName()+"\t读完成"+value);
}
}
读写锁改进
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class Demo{
public static void main(String[] args) {
Book book = new Book();
for (int i = 0; i <5 ; i++) {
String a = String.valueOf(i);
new Thread(()->{
book.put(a,a);
},String.valueOf(i)).start();
}
for (int i = 0; i <5 ; i++) {
String b = String.valueOf(i);
new Thread(()->{
book.get(b);
},String.valueOf(i)).start();
}
}
}
class Book{
private Map<String,String> map = new HashMap<>();
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
public void put(String key,String value){
readWriteLock.writeLock().lock();
try{
System.out.println(Thread.currentThread().getName()+"\t正在写入");
map.put(key, value);
System.out.println(Thread.currentThread().getName()+"\t写入完成");
}catch(Exception e){
e.printStackTrace();
}finally{
readWriteLock.writeLock().unlock();
}
}
public void get(String key){
readWriteLock.readLock().lock();
try{
System.out.println(Thread.currentThread().getName()+"\t正在读"+key);
String value = map.get(key);
System.out.println(Thread.currentThread().getName()+"\t读完成"+value);
}catch(Exception e){
e.printStackTrace();
}finally{
readWriteLock.readLock().unlock();
}
}
}
阻塞队列
接口BlockingQueue
当队列是空的 从队列获取元素的操作会被阻塞 直到队列有元素
当队列式慢的 向队列添加元素的操作会被阻塞 直到队列有位置
为什么需要BlockingQueue
好处是我们不需要关心什么时候需要阻塞线程,什么时候需要唤醒线程,因为这一切BlockingQueue都办了
BlockingQueue的实现类
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class Demo {
public static void main(String[] args) {
//指定队列长度为3
BlockingQueue blockingDeque = new ArrayBlockingQueue(3);
// System.out.println(blockingDeque.add("a"));
// System.out.println(blockingDeque.add("C"));
// System.out.println(blockingDeque.add("D"));
// System.out.println(blockingDeque.add("E"));
// Exception in thread "main" java.lang.IllegalStateException: Queue full
}
}
element方法返回队列头元素 没有就抛出NoSuchElementException异常
peek方法 返回对列头元素 没有就返回null+
线程池
方式获取线程池的3种方式
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Demo {
public static void main(String[] args) {
//可以指定线程池容量 一池3线程
//ExecutorService service = Executors.newFixedThreadPool(3);
//线程池只有一个线程 不能改变 一池1线程
//ExecutorService service = Executors.newSingleThreadExecutor();
//可变的线程数 一池N线程
ExecutorService service = Executors.newCachedThreadPool();
try {
for (int i = 0; i <10 ; i++) {
service.execute(()->{
System.out.println(Thread.currentThread().getName() + "aaa");
});
}
}finally {
service.shutdown();
}
}
}
线程池7大参数
坑爹题
面试问你获取线程池三种方式那种用的最多 ?
都不用 应该自定义 为什么?
源码中 将最大线程数设置为了21亿
阿里巴巴手册规定创建线程的标准方式 可以自己定义7个参数
Executor executor = new ThreadPoolExecutor(,,,,,,);
自定义参数
import java.util.concurrent.*;
public class Demo {
public static void main(String[] args) {
Executor poolExecutor = new ThreadPoolExecutor(
2,
5,
2,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(3),//这个地方不写默认也是21亿
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());//默认拒绝策略
try {
for (int i = 0; i <9 ; i++) {
poolExecutor.execute(()->{
System.out.println(Thread.currentThread().getName() + "aaa");
});
}
}finally {
((ThreadPoolExecutor) poolExecutor).shutdown();
}
}
}
最大接受的线程数=max+queue 超出后报RejectedExecutionException异常
拒绝策略
参数细化
最大线程数是随便的么 ?不是
分为CPU密集型和IO密集型
如果是CPU密集型
cpu核数+1
在java代码中可以获得 CPU核数
System.out.println(Runtime.getRuntime().availableProcessors());//得到内核数
IO密集型
假设有10个线程经常要做IO操作 那线程数一般设置为20 也就是2倍大
转载:https://blog.csdn.net/weixin_44734751/article/details/105444882