> 文档中心 > Java 并发编程(JUC 上)

Java 并发编程(JUC 上)

大家好,我是Java小羽,今天我们聊聊Java并发编程。

1.线程和进程

java可以开启线程吗?

​ 不能开启,start()方法调用的是本地方法start0();

public synchronized void start() {    /     * This method is not invoked for the main method thread or "system"     * group threads created/set up by the VM. Any new functionality added     * to this method in the future may have to also be added to the VM.     *     * A zero status value corresponds to state "NEW".     */    if (threadStatus != 0) throw new IllegalThreadStateException();    /* Notify the group that this thread is about to be started     * so that it can be added to the group's list of threads     * and the group's unstarted count can be decremented. */    group.add(this);    boolean started = false;    try { start0(); started = true;    } finally { try {     if (!started) {  group.threadStartFailed(this);     } } catch (Throwable ignore) {     /* do nothing. If start0 threw a Throwable thenit will be passed up the call stack */ }    }}//调用本地方法private native void start0();

其中native主要是用来加载其他语言的动态链接库的,被native加载的方法是本地方法,由于Java不能直接调用计算机硬件相关的操作,所以通过native关键字修饰,调用c/c++的库来实现效果。

并行和并发

  1. 并行:单核cpu处理多个线程时,在多个线程之间来回跳转操作,看起来就像多个线程同时运行一样。
  2. 并发:只有在多核cpu下才能实现,cpu对多个线程同时进行操作。

​ 买票例子,使用传统的 synchronized锁实现

package JUC.demo1;public class SaleTaskDemo02 {    public static void main(String[] args) {//使用lambam表达式 Ticket ticket=new Ticket(); new Thread(()->{     for (int i = 0; i < 30; i++) {  ticket.sale();     } },"A").start(); new Thread(()->{     for (int i = 0; i < 30; i++) {  ticket.sale();     } },"B").start(); new Thread(()->{     for (int i = 0; i < 30; i++) {  ticket.sale();     } },"C").start();    }}class Ticket{    //属性,方法    private int number=50;    public synchronized void sale(){ if (number>0){     System.out.println(Thread.currentThread().getName()+"出售第"+number--+"张票,还剩"+number+"票"); }    }}

2.Lock锁

什么是Lock锁?

Lock锁的功能和Synchronized锁的功能一样,是用来保证数据唯一性的。

Lock锁又分为:

  • 公平锁:先进来的线程先执行,不可以插队。

  • 非公平锁:可以插队。默认为非公平锁。

public class SaleTaskDemo03 {    public static void main(String[] args) { Ticket ticket=new Ticket(); new Thread(()->{     for (int i = 0; i < 30; i++) {  ticket.sale();     } },"A").start(); new Thread(()->{     for (int i = 0; i < 30; i++) {  ticket.sale();     } },"B").start(); new Thread(()->{     for (int i = 0; i < 30; i++) {  ticket.sale();     } },"C").start();    }}class Ticket1{    //属性,方法    private int number=50;    Lock lock=new ReentrantLock();//创建可重用锁    public void sale(){ lock.lock();//开锁 try {     if (number>0){  System.out.println(Thread.currentThread().getName()+"出售第"+number--+"张票,还剩"+number+"票");     } }catch (Exception e){ }finally {     lock.unlock();//关锁 }    }}

3.生产者和消费者问题

生产者和消费者synchronized版本解决

package JUC.demo1.pc;public class A {    public static void main(String[] args) { Data data = new Data(); new Thread(()->{     for (int i = 0; i < 10; i++) {  try {      data.increment();  } catch (InterruptedException e) {      e.printStackTrace();  }     } },"A").start(); new Thread(()->{     for (int i = 0; i < 10; i++) {  try {      data.decrement();  } catch (InterruptedException e) {      e.printStackTrace();  }     } },"B").start();    }}//等待,业务代码,唤醒class Data{    private static int number=0;    //++1    public synchronized void increment() throws InterruptedException { if (number!=0){     this.wait();//线程等待 } number++; System.out.println(Thread.currentThread().getName()+"->"+number); if(number==1){     this.notifyAll();//唤醒所有线程 }    }    //--1    public synchronized void decrement() throws InterruptedException { if (number!=1){     this.wait();//线程等待 } number--; System.out.println(Thread.currentThread().getName()+"->"+number); if(number==0){     this.notifyAll();//唤醒所有线程 }    }}

A B C D 四个线程,防止虚假唤醒!

package JUC.demo1.pc;public class A {    public static void main(String[] args) { Data data = new Data(); new Thread(()->{     for (int i = 0; i < 10; i++) {  try {      data.increment();  } catch (InterruptedException e) {      e.printStackTrace();  }     } },"A").start(); new Thread(()->{     for (int i = 0; i < 10; i++) {  try {      data.decrement();  } catch (InterruptedException e) {      e.printStackTrace();  }     } },"B").start(); new Thread(()->{     for (int i = 0; i < 10; i++) {  try {      data.increment();  } catch (InterruptedException e) {      e.printStackTrace();  }     } },"C").start(); new Thread(()->{     for (int i = 0; i < 10; i++) {  try {      data.decrement();  } catch (InterruptedException e) {      e.printStackTrace();  }     } },"D").start();    }}//等待,业务代码,唤醒class Data{    private static int number=0;    //++1    public synchronized void increment() throws InterruptedException { while (number!=0){     this.wait();//线程等待 } number++; System.out.println(Thread.currentThread().getName()+"->"+number); if(number==1){     this.notifyAll();//唤醒所有线程 }    }    //--1    public synchronized void decrement() throws InterruptedException { while (number!=1){     this.wait();//线程等待 } number--; System.out.println(Thread.currentThread().getName()+"->"+number); if(number==0){     this.notifyAll();//唤醒所有线程 }    }}

JUC版的生产者和消费者问题

package JUC.demo1.pc;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class B {    public static void main(String[] args) { Data1 data = new Data1(); new Thread(()->{     for (int i = 0; i < 10; i++) {  try {      data.increment();  } catch (InterruptedException e) {      e.printStackTrace();  }     } },"A").start(); new Thread(()->{     for (int i = 0; i < 10; i++) {  try {      data.decrement();  } catch (InterruptedException e) {      e.printStackTrace();  }     } },"B").start(); new Thread(()->{     for (int i = 0; i < 10; i++) {  try {      data.increment();  } catch (InterruptedException e) {      e.printStackTrace();  }     } },"C").start(); new Thread(()->{     for (int i = 0; i < 10; i++) {  try {      data.decrement();  } catch (InterruptedException e) {      e.printStackTrace();  }     } },"D").start();    }}//等待,业务代码,唤醒class Data1{    private static int number=0;    Lock lock=new ReentrantLock();    Condition condition= lock.newCondition();//创建监视器对象    //++1    public  void increment() throws InterruptedException { lock.lock(); try {     while (number!=0){  condition.await();//线程等待     }     number++;     System.out.println(Thread.currentThread().getName()+"->"+number);     if(number==1){  condition.signalAll();//唤醒所有线程     } } catch (Exception e) {     e.printStackTrace(); } finally {     lock.unlock(); }    }    //--1    public  void decrement() throws InterruptedException { lock.lock(); try {     while (number!=1){  condition.await();//线程等待     }     number--;     System.out.println(Thread.currentThread().getName()+"->"+number);     if(number==0){  condition.signalAll();//唤醒所有线程     } } catch (Exception e) {     e.printStackTrace(); } finally {     lock.unlock(); }    }}

condition实现精准线程唤醒

package JUC.demo1.pc;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class C {    public static void main(String[] args) { Data2 data2=new Data2(); new Thread(()->{     for (int i = 0; i < 20; i++) {  data2.printA();     } },"A").start(); new Thread(()->{     for (int i = 0; i < 20; i++) {  data2.printB();     } },"B").start(); new Thread(()->{     for (int i = 0; i < 20; i++) {  data2.printC();     } },"C").start();    }}class Data2{    //A-》B-》C    private  Lock lock=new ReentrantLock();    private Condition conditionA=lock.newCondition();//创建监视器。    private Condition conditionB=lock.newCondition();    private Condition conditionC=lock.newCondition();    private int num=1;    public void printA(){ lock.lock(); try {    //写业务代码     while(num!=1){//这里使用while而不是if防止自旋现象的发生。  conditionA.await();//A线程等待     }     num=2;     System.out.println(Thread.currentThread().getName()+"->AAAAAA");     conditionB.signal();//唤醒B线程 } catch (Exception e) {     e.printStackTrace(); } finally {     lock.unlock(); }    }    public void printB(){ lock.lock(); try {     //写业务代码     while(num!=2){  conditionB.await();//B线程等待     }     num=3;     System.out.println(Thread.currentThread().getName()+"->BBBBB");     conditionC.signal();//唤醒C线程 } catch (Exception e) {     e.printStackTrace(); } finally {     lock.unlock(); }    }    public void printC(){ lock.lock(); try {     //写业务代码     while(num!=3){  conditionC.await();//B线程等待     }     num=1;     System.out.println(Thread.currentThread().getName()+"->CCCCC");     conditionA.signal();//唤醒A线程 } catch (Exception e) {     e.printStackTrace(); } finally {     lock.unlock(); }    }}

4.八锁现象

package JUC.Lock8;import java.util.concurrent.TimeUnit;//1.标准情况下两个线程先打印 发短信还是打电话?   1/发短信 2/打电话//2.sendSms()增加延时的情况下情况下两个线程先打印 发短信还是打电话?   1/发短信 2/打电话public class Tast01 {    public static void main(String[] args) throws InterruptedException { Telephone telephone=new Telephone(); new Thread(()->{//发短信     telephone.sendSms(); },"A").start(); TimeUnit.SECONDS.sleep(1);//休眠一秒 new Thread(()->{//打电话     telephone.call(); },"B").start();    }}class Telephone{//synchronized 锁的对象是方法的调用者。    //两个方法用的是同一个锁,谁先拿到谁执行    public synchronized void sendSms(){ try {     TimeUnit.SECONDS.sleep(1);//休眠一秒 } catch (InterruptedException e) {     e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"发短信");    }    public synchronized void call(){ System.out.println(Thread.currentThread().getName()+"打电话");    }}
package JUC.Lock8;import java.util.concurrent.TimeUnit;//5.增加两个静态同步方法,一个对象,是先打印发短信还是打电话?     发短信。//6.增加两个静态同步方法,两个对象,是先打印发短信还是打电话?     发短信。public class Tast03 {    public static void main(String[] args) throws InterruptedException { Telephone02 telephone1=new Telephone02(); Telephone02 telephone2=new Telephone02(); new Thread(()->{//发短信     telephone1.sendSms(); },"A").start(); TimeUnit.SECONDS.sleep(1);//休眠一秒 new Thread(()->{//打电话     //telephone1.call();     telephone2.call(); },"B").start();    }}//Telephone02是唯一的Class对象,一个类只有唯一的一个Class对象class Telephone02{    //static是类加载的时候就存在的,static锁的是Class。    //synchronized锁的是方法的调用者    public static synchronized void sendSms(){ try {     TimeUnit.SECONDS.sleep(4);//休眠4秒 } catch (InterruptedException e) {     e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"发短信");    }    public static synchronized void call(){ System.out.println(Thread.currentThread().getName()+"打电话");    }}
package JUC.Lock8;import java.util.concurrent.TimeUnit;//7.一个静态同步方法,一个普通同步方法,一个对象,是先打印发短信还是打电话?     打电话//8.一个静态同步方法,一个普通同步方法,两个对象,是先打印发短信还是打电话?     打电话public class Tast04 {    public static void main(String[] args) throws InterruptedException { Telephone03 telephone1=new Telephone03(); Telephone03 telephone2=new Telephone03(); new Thread(()->{//发短信     telephone1.sendSms(); },"A").start(); TimeUnit.SECONDS.sleep(1);//休眠一秒 new Thread(()->{//打电话     //telephone1.call();     telephone2.call(); },"B").start();    }}class Telephone03{    //static锁的是Class模板    public static synchronized void sendSms(){ try {     TimeUnit.SECONDS.sleep(4);//休眠4秒 } catch (InterruptedException e) {     e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"发短信");    }    //synchronized锁的是调用者的对象,是两把锁互不影响。    public synchronized void call(){ System.out.println(Thread.currentThread().getName()+"打电话");    }}

5.集合类不安全

list不安全

package JUC.unsafe;import java.util.*;import java.util.concurrent.CopyOnWriteArrayList;//java.util.ConcurrentModificationException//并发修改异常public class Task01 {    public static void main(String[] args) { //并发下ArrayList不安全吗? /* 解决方案 1.List list=new Vector(); 2.List list= Collections.synchronizedList(new ArrayList()); 3.List list = new CopyOnWriteArrayList();  */ //CopyOnWrite写入时复制 cow 计算机程序设计领域的一种优化策略 //多个线程调用的时候,list,读取的时候,固定的写入覆盖。 //在写入时避免覆盖,造成数据问题 //CopyOnWriteArrayList 比Vector 好在哪里? //1.CopyOnWriteArrayList底层使用的是Lock锁,Vector使用的是synchronized。 //2.CopyOnWriteArrayList 比Vector的效率高 List<String> list = new CopyOnWriteArrayList<>(); for (int i = 1; i < 10; i++) {     new Thread(()->{  list.add(UUID.randomUUID().toString().substring(0,5));  System.out.println(list);     },String.valueOf(i)).start(); }    }}

CopyOnWriteArrayList :写入时复制,只有在要修改list数据的时候,程序会从原来的list数据复制一份,在复制的一份list上进行修改操作,修改完成后覆盖原来的数据。

set不安全

public class ListSet {    public static void main(String[] args) { Set<String> set=new CopyOnWriteArraySet<>(); for (int i = 1; i <10 ; i++) {     new Thread(()->{  set.add(UUID.randomUUID().toString().substring(0,5));  System.out.println(set);     },String.valueOf(i)).start(); }    }}

CopyOnWriteArraySet和CopyOnWriteArrayList的原理一致,只是一个是list集合一个是set集合。

HashSet底层是什么?

HashSet底层是创建了一个HashMap集合,HashSet使用的是HashMap的Key值,HashMap中的Key值是不可重复的。

一下是源码:

public HashSet() {    map = new HashMap<>();}public boolean add(E e) {    return map.put(e, PRESENT)==null;}//PRESENT是一个常量private static final Object PRESENT = new Object();

Map不安全

在多线程下Map集合是不安全的,可以使用ConcurrentHashMap(并发哈希Map)

public class DemoHashMap {    public static void main(String[] args) { Map<String,String> map=new ConcurrentHashMap<>(); for (int i = 1; i <10 ; i++) {     new Thread(()->{  map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0,5));  System.out.println(map);     },String.valueOf(i)).start(); }    }}

6.Callable接口

Callable接口和Runnable接口一样是一种实现线程的接口,但是Callable接口重写的是call方法有返回值,而Runnable接口是重写的run方法没有返回值。

package JUC.callable;import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.Future;import java.util.concurrent.FutureTask;public class CallableTast {    public static void main(String[] args) throws ExecutionException, InterruptedException {  MyThread myThread=new MyThread();//创建对象 FutureTask task=new FutureTask(myThread);//适配类,用于接收运算的返回值 new Thread(task,"A").start();//启动线程 new Thread(task,"B").start();//再次启动线程,结果会被缓存,效率高。 String s= (String) task.get();//这个get方法可能会阻塞,把他放在最后 System.out.println(s);    }}class MyThread implements Callable<String>{    @Override    public String call() throws Exception { System.out.println("call()"); return "aaa";    }}

细节:

1.Callable有缓存

2.get方法可能会阻塞。

7.常用辅助类

7.1CountDownLatch

CountDownLatch减法计数器

package JUC.callable;import java.util.concurrent.CountDownLatch;public class CountDownLachDemo {    public static void main(String[] args) throws InterruptedException { //创建倒计时计数器对象,从6开始倒计时 CountDownLatch count=new CountDownLatch(6); for (int i = 1; i <=6; i++) {     new Thread(()->{  System.out.println(Thread.currentThread().getName()+"-》GO");  //计数器-1  count.countDown();     },String.valueOf(i)).start(); } count.await();//倒计时结束,执行等待。 System.out.println("Over");    }}

7.2CyclicBarrier

CyclicBarrier加法计数器

package JUC.callable;import java.util.concurrent.BrokenBarrierException;import java.util.concurrent.CyclicBarrier;public class CyclicBarrierDemo {    public static void main(String[] args) throws BrokenBarrierException{ //计时器加载到 7 的时候执行 召唤神龙 CyclicBarrier barrier=new CyclicBarrier(7,()->{     System.out.println("召唤神龙"); }); for (int i = 1; i <=7; i++) {     final int temp=i;     new Thread(()->{  System.out.println(Thread.currentThread().getName()+"第"+temp+"个");  try {      barrier.await();//等待  } catch (InterruptedException e) {      e.printStackTrace();  } catch (BrokenBarrierException e) {      e.printStackTrace();  }     },String.valueOf(i)).start(); }    }}

7.Semaphore

Semaphore信号量,就是一种用来控制并发的控制器,就像厕所有3个坑位,来一个人占一个坑,直到三个坑都占满,再来的人就等待。直到一个人出来了,下一个人才能出去。

package JUC.callable;import java.util.concurrent.Semaphore;import java.util.concurrent.TimeUnit;public class SemaphoreDemo {    public static void main(String[] args) { //三个停车位 Semaphore semaphore=new Semaphore(3); for (int i = 1; i <=6 ; i++) {     new Thread(()->{  try {      //获取线程      semaphore.acquire();      System.out.println(Thread.currentThread().getName()+"获取停车位");      TimeUnit.SECONDS.sleep(2);      System.out.println(Thread.currentThread().getName()+"离开停车位");  } catch (InterruptedException e) {      e.printStackTrace();  }finally {      //达到信号量3时释放线程。      semaphore.release();  }     },String.valueOf(i)).start(); }    }}

semaphore.acquire();获取线程,如果已经满了,则等待,直到释放线程。

semaphore.release();会将当前的信号量释放+1,唤醒等待的线程。

作用:1.限流的时候使用。

​ 2.共享资源互斥的时候使用。

8.读写锁

ReentrantReadWriteLock可重用读写锁

package JUC.rw;import java.util.HashMap;import java.util.Map;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantReadWriteLock;public class ReentrantReadWriteLockDemo {    public static void main(String[] args) { MyCacheLock myCacheLock=new MyCacheLock(); //创建10个线程写入 for (int i = 1; i <=10 ; i++) {     final int temp=i;     new Thread(()->{  myCacheLock.put(temp+"",temp+"");     },String.valueOf(i)).start(); } //创建10个线程读取 for (int i = 1; i <=100 ; i++) {     final int temp=i;     new Thread(()->{  myCacheLock.get(temp+"");     },String.valueOf(i)).start(); }    }}class MyCacheLock{    private volatile Map<String,String> map=new HashMap<>();    private ReentrantReadWriteLock lock=new ReentrantReadWriteLock();//定义可重用读写锁    public void put(String s,String v){ //上写锁 lock.writeLock().lock(); try {     System.out.println(Thread.currentThread().getName()+"写入"+s);     map.put(s,v);     System.out.println(Thread.currentThread().getName()+"写入成功"); } catch (Exception e) {     e.printStackTrace(); } finally {     //解锁     lock.writeLock().unlock(); }    }    public void get(String s){ //上读锁 lock.readLock().lock(); try {     System.out.println(Thread.currentThread().getName()+"读取"+s);     Object o=map.get(s);     System.out.println(Thread.currentThread().getName()+"读取成功"); } catch (Exception e) {     e.printStackTrace(); } finally {     //解锁     lock.readLock().unlock(); }    }}

总结:

读的时候可以被多个线程读。(共享锁)lock.readLock()

写的时候只能被一个一个线程写。(独占锁)lock.writeLock()

9.阻塞队列

阻塞队列结构图

Java 并发编程(JUC 上)

什么情况下我们会使用阻塞队列?

  • 多线程并发处理,线程池!
方式 抛出异常 有返回值,不抛出异常 阻塞等待 超时等待
添加 add() offer() put() offer(,)
移除 remove() poll() take() poll(,)
判断队列首部 element() peek() - -
package JUC.Queue;import java.util.concurrent.ArrayBlockingQueue;/*抛出异常*/public class ArrayQueue {    public static void main(String[] args) { task01();    }    public static void task01(){ ArrayBlockingQueue arrayBlockingQueue=new ArrayBlockingQueue<>(3); //抛异常IllegalStateException: Queue full 队列已满异常 //System.out.println(arrayBlockingQueue.add("d")); System.out.println(arrayBlockingQueue.add("a")); System.out.println(arrayBlockingQueue.add("b")); System.out.println(arrayBlockingQueue.add("c")); //NoSuchElementException 队列没有元素异常 //System.out.println(arrayBlockingQueue.remove()); System.out.println(arrayBlockingQueue.remove()); System.out.println(arrayBlockingQueue.remove()); System.out.println(arrayBlockingQueue.remove());    }}
public static void task02(){ /*     不抛异常,有返回值  */ ArrayBlockingQueue arrayBlockingQueue=new ArrayBlockingQueue<>(3);  //添加元素成功返回true,失败返回false arrayBlockingQueue.offer("a"); arrayBlockingQueue.offer("a"); System.out.println(arrayBlockingQueue.offer("a")); System.out.println(arrayBlockingQueue.offer("a")); //删除元素,删除成功返回删除元素,失败返回null System.out.println(arrayBlockingQueue.poll()); System.out.println(arrayBlockingQueue.poll()); System.out.println(arrayBlockingQueue.poll()); System.out.println(arrayBlockingQueue.poll()); //返回队列首部元素 System.out.println(arrayBlockingQueue.peek());    }
public static void task03() throws InterruptedException { /*     队列阻塞(一直阻塞)  */ ArrayBlockingQueue arrayBlockingQueue=new ArrayBlockingQueue<>(3); //添加元素无返回值 arrayBlockingQueue.put("a"); arrayBlockingQueue.put("a"); arrayBlockingQueue.put("a"); //arrayBlockingQueue.put("a"); //删除元素,返回删除元素 System.out.println(arrayBlockingQueue.take()); System.out.println(arrayBlockingQueue.take()); System.out.println(arrayBlockingQueue.take()); //System.out.println(arrayBlockingQueue.take());    }
public static void task04() throws InterruptedException { /*     队列阻塞(超时等待,超时后不再等待)  */ ArrayBlockingQueue arrayBlockingQueue=new ArrayBlockingQueue<>(3);  //添加元素,超过两秒后不再等待。 arrayBlockingQueue.offer("a",2, TimeUnit.SECONDS); arrayBlockingQueue.offer("a",2, TimeUnit.SECONDS); arrayBlockingQueue.offer("a",2, TimeUnit.SECONDS); arrayBlockingQueue.offer("a",2, TimeUnit.SECONDS); //删除元素,超过两秒后不再等待。 arrayBlockingQueue.poll(); arrayBlockingQueue.poll(); arrayBlockingQueue.poll(); arrayBlockingQueue.poll(2,TimeUnit.SECONDS);    }

同步队列SynchronousQueue

官方解释如下图

Java 并发编程(JUC 上)

简单来说SynchronousQueue同步队列,只能放入一个线程,想再插入线程时,只有删除上一个线程才能成功插入,否则阻塞。

package JUC.Queue;import java.util.concurrent.SynchronousQueue;public class SynchronousQueueDemo {    public static void main(String[] args) { SynchronousQueue<String> strings=new SynchronousQueue<>(); new Thread(()->{     try {  //put阻塞等待  strings.put("a");     } catch (InterruptedException e) {  e.printStackTrace();     } },"A").start(); new Thread(()->{     try {  //take阻塞等待  strings.take();     } catch (InterruptedException e) {  e.printStackTrace();     } },"B").start();    }}

10.线程池(重点)

线程池:三大方法,七大参数,4种拒绝策略

池化技术

本质:占用系统的资源,优化资源的使用。

事先准备好一些资源,有人要用就拿走,用完再还回来。

线程池好处:

1.降低资源的消耗

2.提高响应速度

3.方便管理

线程复用,可以控制最大并发数,管理线程。

1.三大方法

package JUC.pool;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class Demo01 {    public static void main(String[] args) { //单个线程池   ExecutorService service = Executors.newSingleThreadExecutor();// //固定大小的线程池// ExecutorService service = Executors.newFixedThreadPool(5);// //弹性线程池,遇强则强// ExecutorService service = Executors.newCachedThreadPool(); try {     for (int i = 0; i < 10; i++) {  //用线程池创建线程  service.execute(()->{      System.out.println(Thread.currentThread().getName()+"->OK");  });     } } catch (Exception e) {     e.printStackTrace(); } finally {     //关闭线程池     service.shutdown(); }    }}

阿里编程手册:

Java 并发编程(JUC 上)

2.七大参数

package JUC.pool;import java.util.concurrent.*;public class Demo01 {    public static void main(String[] args) { //创建线程池执行器,工作的时候常用 ExecutorService service=new ThreadPoolExecutor(  2,//线程核心数,最小运行的线程数  5,//最大线程数  2L,//超过时长没有人调用就释放  TimeUnit.SECONDS,//超时单位  new LinkedBlockingDeque<Runnable>(3),//阻塞双端队列  Executors.defaultThreadFactory(),//线程工厂,创建线程的,一般默认  new ThreadPoolExecutor.AbortPolicy()//拒绝策略 ); try {     //最大承载数=Deque阻塞队列数+max最大核心数     for (int i = 1; i <=9; i++) {  //用线程池创建线程  service.execute(()->{      System.out.println(Thread.currentThread().getName()+"->OK");  });     } } catch (Exception e) {     e.printStackTrace(); } finally {     //关闭线程池     service.shutdown(); }    }}

3.四种拒绝策略

/*中止策略* new ThreadPoolExecutor.AbortPolicy()//线程池满了,还有线程来,不处理,抛异常  调用者运行策略* new ThreadPoolExecutor.CallerRunsPolicy()//线程池满了,还有线程来,哪里来的回那里去。  丢弃策略* new ThreadPoolExecutor.DiscardPolicy()//线程池满了,丢掉任务,不抛异常。  丢弃老的策略* new ThreadPoolExecutor.DiscardOldestPolicy()//队列满了,尝试与最先进来的线程竞争,竞争成功执行,反之丢掉,不抛异常*/

CPU密集型和IO密集型

最大线程到底该如何定义

1.CPU密集型:电脑是几核就是几,可以保持CPU的效率最高

2.IO密集型: > 判断你程序中十分耗IO的线程。(一般为IO线程的两倍)

Runtime.getRuntime().availableProcessors();获取当前电脑cpu核心。

想了解更多的Java知识,可以关注我的微信公众号Java小羽。

在这里插入图片描述