1、java.util工具包、包、分类
业务:普通的线程代码 Thread
Runnable:没有返回值,效率相比Callable相对较低
1、进程:一个程序,程序的集合;
2、线程:开了一个进程(Typora),写字、自动保存(线程负责)
对于Java而言,开启线程的三种方式:Thread、Runnable、Callable
//本地方法,底层的C++,Java无法直接操作硬件
private native void start();
3、并发和并行
package JUC_Study;
public class Test1 {
public static void main(String[] args) {
//获取CPU核数
//CPU密集型,IO密集型
System.out.println(Runtime.getRuntime().availableProcessors());
}
}
4、线程的状态:新生、运行、阻塞、等待、超时等待、终止
5、wait和sleep的区别
1、传统Synchronized
package JUC_Study;
//基本的卖票例子。真正的多线程开发,公司中的开发,降低耦合性
public class SaleTicketDemo01 {
//线程就是一个单独的资源类,没有任何附属的操作
public static void main(String[] args) {
//并发:多线程操作同一个资源类,把资源类丢入线程
Ticket ticket = new Ticket();
//lambda表达式:()->{代码}
new Thread(()->{
for (int i = 0; i < 40; i++) {
ticket.sale();
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 40; i++) {
ticket.sale();
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 40; i++) {
ticket.sale();
}
},"C").start();
}
}
//资源类:属性、方法 OOP
class Ticket{
private int number = 50;
private int i = 1;
//卖票的方法
public synchronized void sale(){
if(number>0){
number--;
System.out.println(Thread.currentThread().getName()+"卖出了"+i+"票,剩余:"+number);
i++;
}
}
}
2、JUC中LOCK接口
Lock l = ...; l.lock(); try { // access the resource protected by this lock } finally { l.unlock(); }
所有已知实现类:
ReentrantLock , ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLock
公平锁:十分公平,必须先来后到
非公平锁:不公平,可以插队(默认)
package JUC_Study;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class SaleTicketDemo02 {
public static void main(String[] args) {
//并发:多线程操作同一个资源类,把资源类丢入线程
Ticket2 ticket = new Ticket2();
new Thread(()->{
for (int i = 0; i < 40; i++){
ticket.sale();
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 40; i++) {
ticket.sale();
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 40; i++) {
ticket.sale();
}
},"C").start();
}
}
//资源类:属性、方法 OOP
//Lock三部曲
//1.new ReentrantLock() 2.加锁 lock.lock(); 3.解锁: finally ==>lock.unlock()
class Ticket2{
private int number = 40;
Lock lock = new ReentrantLock();
public void sale(){
lock.lock();
try {
if(number>0){
System.out.println(Thread.currentThread().getName()+"卖出了"+(number--)+"票,剩余:"+number);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
3、Synchroized和Lock的区别
1.判断是否等待,2.业务代码,3.通知下一个线程
1、Synchroized 版 wait notify
package JUC_Study.pc;
/*
* 线程之间的通信问题:生产者和消费者问题 等待唤醒, 通知唤醒
* 线程交替执行 A B操作同一个变量 num=0
* A num+1
* B num-1
*
* */
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 int number = 0;
//方法 +1
public synchronized void increment() throws InterruptedException {
while (number!=0){ //0才干活
//等待
this.wait();
}
number++;
System.out.println(Thread.currentThread().getName()+"=>"+number);
//通知其他线程,我+1完毕
this.notifyAll();
}
//方法 -1
public synchronized void decrement() throws InterruptedException {
while (number==0){//1才干活,1-1=0
//等待
this.wait();
}
number--;
System.out.println(Thread.currentThread().getName()+"=>"+number);
//通知其他线程,我-1完毕
this.notifyAll();
}
}
2、juc lock版生产者和消费者问题
package JUC_Study.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) {
Data2 data = new Data2();
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 Data2{
private int number = 0;
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
//方法 +1
public void increment() throws InterruptedException {
try {
lock.lock();
//业务代码
while (number != 0) { //0才干活
//等待
condition.await();
}
number++;
System.out.println(Thread.currentThread().getName() + "=>" + number);
//通知其他线程,我+1完毕
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
//方法 -1
public void decrement() throws InterruptedException {
try {
lock.lock();
while (number==0){//1才干活,1-1=0
//等待
condition.await();
}
number--;
System.out.println(Thread.currentThread().getName()+"=>"+number);
//通知其他线程,我-1完毕
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
// condition.await();等待
// condition.signalAll();唤醒
3、Condition 精准的通知和唤醒线程
package JUC_Study.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) {
Data3 data = new Data3();
//有序执行线程,A->B->C
new Thread(()->{
for (int i = 0; i < 10; i++) {
data.printA();
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
data.printB();
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
data.printC();
}
},"C").start();
}
}
class Data3{//资源类
private Lock lock = new ReentrantLock();
private Condition condition1= lock.newCondition();
private Condition condition2= lock.newCondition();
private Condition condition3= lock.newCondition();
private int number =1; //1A 2B 3C
public void printA(){
lock.lock();
try {
while (number != 1){
//等待
condition1.await();
}
System.out.println(Thread.currentThread().getName()+"=>AAAA");
//唤醒指定人,B
number = 2;
condition2.signal();//唤醒2,就是唤醒B,精准唤醒
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printB(){
lock.lock();
try {
while (number!=2){
//等待
condition2.await();
}
System.out.println(Thread.currentThread().getName()+"=>BBBB");
number = 3;
condition3.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printC(){
lock.lock();
try {
while (number!=3){
//等待
condition3.await();
}
System.out.println(Thread.currentThread().getName()+"=>CCCC");
number = 1;
condition1.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
深刻理解锁
1、代码测试:
package JUC_Study.Lock8;
/*
* 8锁就是关于锁的八个问题
* 1、标准情况下,两个线程先打印发短信还是打电话? :先发短信再打电话
* 2、senSms 四秒延迟 : 依然是先发短信后打电话
* 原因:synchronized 锁的对象是方法的调用者,两个方法用的是同一个锁,谁先拿到谁执行
*
*
* */
import java.util.concurrent.TimeUnit;
public class Test1 {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(()->{
phone.senSms();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone.call();
},"B").start();
}
}
class Phone{
public synchronized void senSms(){
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
}
package JUC_Study.Lock8;
import java.util.concurrent.TimeUnit;
/*
* 3、增加了一个普通方法后,是先执行发短信还是hello?
*不一定。普通方法不受锁的限制,CPU会判断间隔时间,如果判断执行hello线程的延时时间比发短信短,,那么就算先调用发短信,也还是先打电话。
* 如果延时时间一样,先执行有锁的。
*
*4、两个对象,两个同步方法:两把锁,按时间来,打电话延时小,所以先打电话
*
* */
public class Test2 {
public static void main(String[] args) {
//两个对象
Phone2 phone2 = new Phone2();
Phone2 phone1 = new Phone2();
new Thread(()->{
phone1.senSms();
},"A").start();
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone2.call();
},"B").start();
}
}
class Phone2{
public synchronized void senSms(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
//没有锁,不受锁的影响
public void hello(){
System.out.println("hello");
}
}
package JUC_Study.Lock8;
import java.util.concurrent.TimeUnit;
/*5、 增加两个静态的同步方法,只有一个对象:先发短信再打电话。
static:静态方法,类一加载就有了!Class,Phone3唯一的一个class对象,锁的是Class
6、两个对象,增加两个静态的同步方法 :先发短信再打电话锁的是Class,两个对象的Class类模板只有一个。
*
*
*
* */
public class Test3 {
public static void main(String[] args) {
//两个对象
Phone3 phone1= new Phone3();
Phone3 phone2 = new Phone3();
new Thread(()->{
phone1.senSms();
},"A").start();
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone2.call();
},"B").start();
}
}
class Phone3{
public static synchronized void senSms(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public static synchronized void call(){
System.out.println("打电话");
}
//没有锁,不受锁的影响
public static void hello(){
System.out.println("hello");
}
}
package JUC_Study.Lock8;
import java.util.concurrent.TimeUnit;
/*
* 7、一个静态同步方法,一个普通同步方法,一个对象:先打电话(普通)后发短信(静态)
* 8、一个静态同步方法,一个普通同步方法,两个对象:先打电话(普通)后发短信(静态)
*
*
*
* */
public class Test4 {
public static void main(String[] args) {
//两个对象
Phone4 phone1= new Phone4();
Phone4 phone2= new Phone4();
new Thread(()->{
phone1.senSms();
},"A").start();
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone2.call();
},"B").start();
}
}
class Phone4{
//静态同步方法
public static synchronized void senSms(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
//普通同步方法
public synchronized void call(){
System.out.println("打电话");
}
//没有锁,不受锁的影响
public static void hello(){
System.out.println("hello");
}
}
2、小结
1、List不安全
java.util.ConcurrentModificationException 并发修改异常!
解决方案:
1):并发下,ArrayList不安全,把new ArrayList 换成 new Vector()
2): 用集合工具类,Listlist =Collections.synchronizedList(new ArrayList<>());
3):JUC里的类, Listlist =new CopyOnWriteArrayList<>();
CopyOnWrite:写入时赋值,COW 计算机程序设计领域的一种优化策略,多个线程调用时,list,读取的时候,固定的,写入(覆盖),在写入的时候避免覆盖,造成数据问题
package JUC_Study.unsafe;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
/*
* java.util.ConcurrentModificationException 并发修改异常!
*一、解决方案:
* 1):并发下,ArrayList不安全,把new ArrayList 换成 new Vector()
* 2): 用集合工具类,Listlist =Collections.synchronizedList(new ArrayList<>());
* 3):JUC里的类, Listlist =new CopyOnWriteArrayList<>();
*二、CopyOnWrite:写入时赋值,COW 计算机程序设计领域的一种优化策略,多个线程调用时,list,读取的时候,固定的,写入(覆盖)
* 在写入的时候避免覆盖,造成数据问题
*
*
* */
public class ListTest {
public static void main(String[] args) {
//并发下,ArrayList不安全
List<String>list =new CopyOnWriteArrayList<>();
for (int i = 1; i <= 100; i++) {
new Thread(()->{
list.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(list);
},String.valueOf(i)).start();
}
}
}
2、Set不安全
package JUC_Study.unsafe;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArraySet;
/*
* java.util.ConcurrentModificationException 并发修改异常
* 解决方案:
* 1)Setset = Collections.synchronizedSet(new HashSet<>());
* 2) Setset = new CopyOnWriteArraySet<>();
*
*
*
* */
public class SetTest {
public static void main(String[] args) {
Set<String>set = new CopyOnWriteArraySet<>();
for (int i = 0; i < 30; i++) {
new Thread(()->{
set.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(set);
},String.valueOf(i)).start();
}
}
}
HashSet底层是HashMap,add set 本质就是map key,是无法重复的
3、Map不安全
package JUC_Study.unsafe;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
/*
* java.util.ConcurrentModificationException
* 解决方案:
* 1) Mapmap = new ConcurrentHashMap<>();
*
* */
public class MapTest {
public static void main(String[] args) {
//map
Map<String,String>map = new ConcurrentHashMap<>();
for (int i = 1; i <= 30; i++) {
new Thread(()->{
map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0,5));
System.out.println(map);
},String.valueOf(i)).start();
}
}
}
1、可以有返回值
2、可以抛出异常
3、方法不同
package JUC_Study.callable;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class CallableTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyThread thread = new MyThread();
FutureTask futureTask = new FutureTask(thread);
new Thread(futureTask,"A").start();
String o = (String) futureTask.get();//返回值 这个get方法可能会产生阻塞,把它放到最后
System.out.println(o);
}
}
class MyThread implements Callable<String>{
@Override
public String call() throws Exception {
System.out.println("call()");
return "45678";
}
}
细节:
减法计数器
package JUC_Study.add;
import java.util.concurrent.CountDownLatch;
// 计数器
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
//总数是6
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 1; i <= 6; i++) {
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"Go Out");
countDownLatch.countDown();
},String.valueOf(i)).start();
}
countDownLatch.await();//等待计数器归零,然后再向下执行
System.out.println("close door");
}
}
这是一个加法计数器
package JUC_Study.add;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierDemo {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{
System.out.println("召唤神龙成功!");//等待收集到7,才输出召唤成功
});
for (int i = 1; i <= 7; i++) {
final int temp = i;//lambda表达式拿不到i,必须通过final
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"收集"+temp+"颗龙珠");
try {
cyclicBarrier.await();//等待
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
}
}
抢车位,限流也可以用
package JUC_Study.add;
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(()->{
//acquire() 等待 release()释放
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 {
semaphore.release();
}
},String.valueOf(i)).start();
}
}
}
ReadWriteLock :读可以被多线程同时读,写的时候只能有一个线程写
代码测试:
package JUC_Study.RW;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/*
* ReadWriteLock
*
*
*
* */
public class ReadWriteLockDemo {
public static void main(String[] args) {
MyCacheLock myCache = new MyCacheLock();
for (int i = 1; i <= 5; i++) {
final int temp = i;
new Thread(()->{
myCache.put(temp+"",temp+"");
},String.valueOf(i)).start();
}
for (int i = 1; i <= 5; i++) {
final int temp = i;
new Thread(()->{
myCache.get(temp+"");
},String.valueOf(i)).start();
}
}
}
//自定义缓存
class MyCacheLock{
private volatile Map<String,Object>map = new HashMap<>();
//new一个读写锁,更加细粒度的控制
private ReadWriteLock lock = new ReentrantReadWriteLock();
//存,写,写入的时候只希望同时只有一个线程写
public void put(String key,Object value){
lock.writeLock().lock();//加写锁
try {
System.out.println(Thread.currentThread().getName()+"写入"+key);
map.put( key,value);
System.out.println(Thread.currentThread().getName()+"写入ok");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.writeLock().unlock();
}
}
//取,读,所有人都可以读
public void get(String key){
lock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName()+"读取"+key);
Object o = map.get(key);
System.out.println(Thread.currentThread().getName()+"读取ok");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.readLock().unlock();
}
}
}
1、不得不阻塞
写入:如果队列满了,就必须阻塞等待
取:如果队列是空的,必须阻塞等待生产
2、BlockingQueue不是新东西。什么情况下使用阻塞队列?
3、学会使用队列
添加、移除
四组API
package JUC_Study.BQ;
import java.util.concurrent.ArrayBlockingQueue;
public class Test {
public static void main(String[] args) {
test1();
}
//抛出异常
public static void test1(){
//队列的大小
ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
System.out.println(blockingQueue.add("a"));
System.out.println(blockingQueue.add("b"));
System.out.println(blockingQueue.add("c"));
//已经满了,抛出异常:IllegalStateException: Queue full,队列已满
//System.out.println(blockingQueue.add("d"));
System.out.println(blockingQueue.remove());
System.out.println(blockingQueue.remove());
System.out.println(blockingQueue.remove());//按顺序移除,a,b,c
//如果没有元素,抛出异常:java.util.NoSuchElementException
}
}
public static void test2(){
ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
System.out.println(blockingQueue.offer("a"));
System.out.println(blockingQueue.offer("b"));
System.out.println(blockingQueue.offer("c"));
//满了不抛出异常,返回一个false
System.out.println(blockingQueue.offer("d"));
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());//null,也不会抛出异常
}
//检测队首元素,返回队首元素
blockingQueue.peek()
blockingQueue.element()
public static void test3() throws InterruptedException {
ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
blockingQueue.put("a");
blockingQueue.put("b");
blockingQueue.put("c");
//队列没有位置,一直阻塞,一直等待(程序不结束)
//blockingQueue.put("d");
System.out.println(blockingQueue.take());//a
}
public static void test4() throws InterruptedException {
ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
blockingQueue.offer("a");
blockingQueue.offer("b");
blockingQueue.offer("c");
blockingQueue.offer("d", 2,TimeUnit.SECONDS);//等待超过2s退出
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll(2,TimeUnit.SECONDS));
}
4、 SynchronousQueue同步队列
没有容量,进去一个元素,必须等待取出来之后,才能再往里面放一个元素!
put,take
package JUC_Study.BQ;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
//同步队列
public class SynchronousQueueDemo {
public static void main(String[] args) {
SynchronousQueue<String> synchronousQueue = new SynchronousQueue<>();//同步队列
new Thread(()->{
try {
System.out.println(Thread.currentThread().getName()+"put 1");
synchronousQueue.put("1");
System.out.println(Thread.currentThread().getName()+"put 2");
synchronousQueue.put("2");
System.out.println(Thread.currentThread().getName()+"put 3");
synchronousQueue.put("3");
} catch (InterruptedException e) {
e.printStackTrace();
}
},"T1").start();
new Thread(()->{
try {
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName()+synchronousQueue.take());
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName()+synchronousQueue.take());
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName()+synchronousQueue.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
},"T2").start();
}
}
//输出结果:
T1put 1
T21
T1put 2
T22
T1put 3
T23
//进去一个元素后,只有取出来才能再往里放。SynchronousQueue不能存储
1、程序的运行,本质:占用系统的资源!优化资源的使用—>池化技术
如:线程池、连接池、内存池、对象池,创建和销毁十分浪费资源
2、 池化技术:实现准备好一些资源,有人要用,就来这里拿,用完之后还给我
3、 线程池的好处:
4、线程池三大方法 :
public static void main(String[] args) {
ExecutorService threadPool = Executors.newSingleThreadExecutor();
//线程池用完,程序结束,关闭线程池
try {
for (int i = 0; i < 10; i++) {
//使用了线程池之后,用线程池来创建线程
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName()+"ok");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
threadPool.shutdown();
}
}
5、 线程池七大参数 :
核心线程数:就是一直有的,最小线程数。
6、自定线程池
package JUC_Study.pool;
import java.util.concurrent.*;
public class Demo02 {
public static void main(String[] args) {
//自定义线程池,七大参数
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
2,
5,
3,
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(3),//阻塞队列
Executors.defaultThreadFactory(),//线程工厂
new ThreadPoolExecutor.AbortPolicy());//拒绝策略的一种,银行满了,还有人进来,就不处理这个人并抛出异常
try {
//最大承载:阻塞队列+最大核心线程数
for (int i = 0; i < 9; i++) {
//使用了线程池之后,用线程池来创建线程
threadPoolExecutor.execute(()->{
System.out.println(Thread.currentThread().getName()+"ok");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
threadPoolExecutor.shutdown();
}
}
}
7、四种拒绝策略
8、线程池的最大线程数应该该如何设置:
System.out.println(Runtime.getRuntime().availableProcessors());//获取CPU核数
1、函数型接口:FunctionalInterface,简化编程模型
public static void main(String[] args) {
//工具类:输出输入的值
// Function function = new Function() {
// @Override
// public String apply(String str) {
// return str;
// }
// };
//简化
Function function = (str)->{return str;};
System.out.println(function.apply("xqh"));
}
2、断定型接口(有一个输入参数,返回值只能是布尔值)
public static void main(String[] args) {
//判断字符串是否为空
// Predicate predicate = new Predicate() {
// @Override
// public boolean test(String str) {
// return str.isEmpty();
// }
// };
//简化
Predicate<String> predicate=(str)->{return str.isEmpty();};
System.out.println(predicate.test("x"));//false 不为空
}
3、消费型接口
public static void main(String[] args) {
// Consumerconsumer = new Consumer() {
// @Override
// public void accept(String str) {
// System.out.println(str);
//
// }
// };
// consumer.accept("ass");
//简化
Consumer<String>consumer = (str)->{
System.out.println(str);
};
consumer.accept("xqh");
}
4、供给型接口
public static void main(String[] args) {
// Supplier supplier = new Supplier() {
// @Override
// public Integer get() {
// return 1024;
// }
// };
// System.out.println(supplier.get());
//简化
Supplier supplier = ()->{return 1024;};
System.out.println(supplier.get());
}
1、什么是 Stream流式计算?
2、代码测试
package JUC_Study.Stream;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
/*
* 题目要求:
* 现在有5个用户,筛选:
* 1.ID必须是偶数
* 2.年龄必须大于23岁
* 3.用户名转为大写字母
* 4.用户名字母倒着排序
* 5.只输出一个用户
* */
public class Test01 {
public static void main(String[] args) {
User u1 = new User(1, "a", 21);
User u2 = new User(2, "b", 22);
User u3 = new User(3, "c", 23);
User u4 = new User(4, "d", 24);
User u5 = new User(6, "e", 25);
//集合就是存储
List<User> list = Arrays.asList(u1, u2, u3, u4, u5);
//计算交给Stream流
list.stream()
.filter(u -> {return u.getId() % 2 == 0;})
.filter(u->{return u.getAge()>23;})
.map(u->{return u.getName().toUpperCase();})
.sorted((uu1,uu2)->{return uu2.compareTo(uu1);})
.limit(1)
.forEach(System.out::println);
}
}
1、什么是ForkJoin
2、ForkJoin特点:工作窃取
1、Future 设计的初衷:对将来的某个事件的结果进行建模
package JUC_Study.future;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
/*异步调用 CompletableFuture
*异步执行
* 成功回调
* 失败回调
*
* */
public class Demo01 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//发起一个请求
//没有返回值的runAsync异步回调
CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(()->{
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"runAsync=>Void");
});
System.out.println("1111");
completableFuture.get();//阻塞获取执行结果
}
}
1、Volatile的理解
2、JMM
3、线程:工作内存、主内存
4、八种操作
load , read , use , assign , write , store , lock , unlock
1、保证可见性
package JUC_Study.tvolatile;
import java.util.concurrent.TimeUnit;
public class JMMDemo {
private volatile static int num =0;
public static void main(String[] args) {//main线程
new Thread(()->{//线程1
while (num == 0){}
}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
num = 1;
System.out.println(num);
//输出了1,但是程序并没有停止
//不加 volatile程序就会死循环,加了 volatile会停止,因为保证了可见性
}
}
2、不保证原子性
原子性:ACID,不可分割
线程A在执行任务的时候,不能被打扰,也不能被分割,要么同时成功,要么同时失败
package JUC_Study.tvolatile;
public class Demo02 {
private volatile static int num = 0;
public static void add(){
num++;
}
public static void main(String[] args) {
//理论上num结果应该为2万
for(int i = 1;i<=20;i++){
new Thread(()->{
for (int i1 = 0; i1 < 1000; i1++) {
add();
}
}).start();
}
while (Thread.activeCount()>2){
Thread.yield();
}
System.out.println(Thread.currentThread().getName()+" "+num);
}
}
//加Synchronize可以,加volatile不行
使用原子类,解决原子性问题
private volatile static AtomicInteger num = new AtomicInteger();
public static void add(){
num.getAndIncrement();
}
3、指令重排
4、Volatile是可以保证可见性,不能保证原子性,由于内存屏障,可以保证避免指令重排的现象产生!
1、饿汉式
package JUC_Study.Singal;
//饿汉式单例
public class Hungry {
//可能会浪费空间
private byte[]data1 = new byte[1024*1024];
private Hungry(){
}
private final static Hungry HUNGRY = new Hungry();
public static Hungry getInstance(){
return HUNGRY;
}
}
2、懒汉式
package JUC_Study.Singal;
public class lazy {
private lazy(){
System.out.println(Thread.currentThread().getName()+"ok");
}
//双重检测锁模式的 懒汉式单例 DCL懒汉式
private static lazy lazy;
public static lazy getInstance(){
if(lazy == null){
synchronized (lazy.class){
if(lazy == null){
lazy = new lazy();
}
}
}
return lazy;
}
//多线程并发
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()->{
lazy.getInstance();
}).start();
}
}
}
公平锁:非常公平,不能插队
非公平锁:非常不公平,可以插队(默认)
Lock lock = new ReentrantLock();//默认是非公平锁
package JUC_Study.Lock;
import java.util.concurrent.atomic.AtomicReference;
//自旋锁
public class Demo01 {
AtomicReference<Thread> atomicReference=new AtomicReference<>();
//加锁
public void myLock(){
Thread thread =Thread.currentThread();
System.out.println(Thread.currentThread().getName()+"==>myLock");
//自旋锁
while (atomicReference.compareAndSet(null,thread)){
}
}
//解锁
public void unLock(){
Thread thread =Thread.currentThread();
System.out.println(Thread.currentThread().getName()+"==>myUnLock");
atomicReference.compareAndSet(thread,null);
}
}