JUC编程入门(高并发)
JUC编程
与JUC编程相关的包
一.线程和进程
一个进程往往包含多个线程,至少包含一个线程
java默认有几个线程?
mian线程和GC线程(垃圾回收)
对于java而言:Thread、Runnable、Callable
一般是他们来开启进程
java真的能开启线程么?
java是不能开启线程的
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 */}}
}
//调用start0 native是本地方法,需要去调用C++操作硬件的,java实现不了
private native void start0();
并行、并发
并发编程:并行、并发
并发(多线程操作同一个资源)
·CPU一核,模拟出来多条线程,快速交替
并行(多个人一起行走)
·CPU多核,多个线程可以同时进行
public class Test1 {public static void main(String[] args) {//获取CPU的核数//CPU密集型,IO密集型System.out.println(Runtime.getRuntime().availableProcessors());}
}
并发编程的本质:充分利用CPU的资源
线程的几个状态
public enum State {//新建NEW,//运行RUNNABLE,//阻塞BLOCKED,//等待WAITING,//超时等待TIMED_WAITING,//终止TERMINATED;
}
wait/sleep区别
1.来自不同的类
wait=》Object
sleep=》Thread
2.关于锁的释放
wait回释放锁的,而sleep是不会释放的
3.使用的范围不同
wait:必须在同步代码块中
sleep:可以在任何地方使用
4.是否需要捕获异常
wait不需要捕获异常
sleep必须要捕获异常(因为他可能会有超时等待)
二.Lock锁
传统的Synchronized
public class SaleTicketDemo01 {public static void main(String[] args) {//并发,多线程操作同一个资源类Ticket ticket = new Ticket();new Thread(()->{for (int i=0;i<60;i++) {ticket.sale();}},"A").start();new Thread(()->{for (int i=0;i<60;i++) {ticket.sale();}},"B").start();new Thread(()->{for (int i=0;i<60;i++) {ticket.sale();}},"C").start();}
}
//资源类 OOP
class Ticket{//属性,方法private int number = 50;//买票的方式public synchronized void sale(){if (number>0){System.out.println(Thread.currentThread().getName()+"卖出了"+(number--)+"票,还剩"+number+"张");}}
}
如果我们的买票方法没有synchronized修饰,则会出乱,没有顺序(synchronized也是非公平锁)
Lock接口
公平锁:可以先来后到:必须排队
非公平锁:不公平,可以插队(默认使用非公平锁)
public class SaleTicketDemo02 {public static void main(String[] args) {//并发,多线程操作同一个资源类Ticket2 ticket = new Ticket2();new Thread(()->{ for (int i=0;i<60;i++) ticket.sale(); },"A").start();new Thread(()->{for (int i=0;i<60;i++) {ticket.sale();}},"B").start();new Thread(()->{for (int i=0;i<60;i++) {ticket.sale();}},"C").start();}
}
//lock3部曲
//1.new ReentrantLock()
//2.lock.lock()加锁
//3.finally { //解锁 lock.unlock(); }
//资源类 OOP
class Ticket2{//属性,方法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){e.printStackTrace();}finally {//解锁lock.unlock();}}
}
相当于手动挡的synchronized
Synchronized和Lock区别
1.Synchroized是一个内置的Java关键字,Lock是一个类
2.Synchroized无法判断读取锁的状态,Lock可以判断是否获取到锁
3.Synchroized会自动释放锁,lock必须手动释放锁,如果不释放锁,就会死锁
4.Synchroized 线程1(获得锁:阻塞)、线程2(等待锁,傻等),而lock锁不会傻等(lock.trylock()尝试获取锁)
5.Synchroized 可重入锁,不可中断的,非公平锁;
lock锁,也是可重入锁,可以判断锁状态,可以自己设置是非公平锁还是公平锁
6.Synchroized 适合锁少量的代码同步问题,Lock锁适合锁大量的同步代码
什么是锁,如何判断锁的是谁?
三.生产者和消费者问题
synchronized版本
package com.hkd.pc;/*** @author 王庆华* @version 1.0* @date 2020/11/13 11:50* @Description 线程之间的通信问题:生产者和消费者问题 等待唤醒,通知唤醒* @pojectname 线程交替执行 A B 操作同一个变量 num = 0* A num+1 B num-1*/
public class A {public static void main(String[] args) {Date date = new Date();new Thread(()->{for (int i=0;i<10;i++){try {date.increment();} catch (InterruptedException e) {e.printStackTrace();}}},"A").start();new Thread(()->{for (int i=0;i<10;i++){try {date.decrement();} catch (InterruptedException e) {e.printStackTrace();}}},"B").start();}
}
//判断等待,通知,业务
class Date{public int number = 0;//+1public synchronized void increment() throws InterruptedException {if (number!=0) {//等待this.wait();}number++;//通知其他线程,我+1完毕了System.out.println(Thread.currentThread().getName()+"=>"+number);this.notifyAll();}public synchronized void decrement() throws InterruptedException {if (number==0){//等待this.wait();}number--;//通知其他线程我-1完毕了System.out.println(Thread.currentThread().getName()+"=>"+number);this.notifyAll();}
}
问题:如果存在A B C D四个线程呢,线程还安全么
虚假唤醒问题
if改为while判断
即可解决虚假唤醒问题
JUC版本
class BoundedBuffer {final Lock lock = new ReentrantLock();final Condition notFull = lock.newCondition(); final Condition notEmpty = lock.newCondition(); final Object[] items = new Object[100];int putptr, takeptr, count;public void put(Object x) throws InterruptedException {lock.lock(); try {while (count == items.length)notFull.await();items[putptr] = x;if (++putptr == items.length) putptr = 0;++count;notEmpty.signal();} finally { lock.unlock(); }}public Object take() throws InterruptedException {lock.lock(); try {while (count == 0)notEmpty.await();Object x = items[takeptr];if (++takeptr == items.length) takeptr = 0;--count;notFull.signal();return x;} finally { lock.unlock(); }}}
代码实现:
package com.hkd.pc;import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;/*** @author 王庆华* @version 1.0* @date 2020/11/13 12:14* @Description TODO* @pojectname 线程相关*/
public class B {public static void main(String[] args) {Date date = new Date();new Thread(()->{for (int i=0;i<10;i++){try {date.increment();} catch (InterruptedException e) {e.printStackTrace();}}},"A").start();new Thread(()->{for (int i=0;i<10;i++){try {date.decrement();} catch (InterruptedException e) {e.printStackTrace();}}},"B").start();new Thread(()->{for (int i=0;i<10;i++){try {date.increment();} catch (InterruptedException e) {e.printStackTrace();}}},"C").start();new Thread(()->{for (int i=0;i<10;i++){try {date.decrement();} catch (InterruptedException e) {e.printStackTrace();}}},"D").start();}
}//判断等待,通知,业务
class Date1{public int number = 0;//+1Lock lock = new ReentrantLock();Condition condition = lock.newCondition();public void increment() throws InterruptedException {lock.lock();try {while (number!=0) {//等待condition.await();//等待}number++;//通知其他线程,我+1完毕了System.out.println(Thread.currentThread().getName()+"=>"+number);condition.signalAll();} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}public void decrement() throws InterruptedException {lock.lock();try {while (number==0) {//等待condition.await();//等待}number--;//通知其他线程,我-1完毕了System.out.println(Thread.currentThread().getName()+"=>"+number);condition.signalAll();} catch (Exception e) {e.printStackTrace();}finally {lock.unlock();}}
}
任何一个新技术,绝不是仅仅只是覆盖了原来的技术,而是优势和补充
问题:
不是ABCD的顺序
Condition精准的通知和唤醒技术
有序性
代码测试
package com.hkd.pc;import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;/*** @author 王庆华* @version 1.0* @date 2020/11/13 19:12* @Description TODO* @pojectname 线程相关*/
public class C {public static void main(String[] args) {Data3 data = new Data3();//A执行完 调用B,B执行完调用C ,C执行完调用Anew 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();}
}
//资源类 lock锁
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;//1 A 2B 3Cpublic void printA(){lock.lock();try {//业务 判断 执行while (number!=1){condition1.await();}System.out.println(Thread.currentThread().getName()+"=>AAA");//唤醒,唤醒指定的人number=2;condition2.signal();} 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()+"=>AAA");//唤醒,唤醒指定的人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()+"=>AAA");//唤醒,唤醒指定的人number=1;condition1.signal();} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}
}
保证了我们的有序性
四.八锁现象
对象、Class
情况一
synchronized关键字
锁的对象是方法的调用者
package com.hkd.lock8;import java.util.concurrent.TimeUnit;/*** @author 王庆华* @version 1.0* @date 2020/11/13 19:28* @Description TODO* //1.标准情况下:先打印是发短信还是打电话?--------》发短信* 2.我们发短信业务中暂停3S,现在先打印是发短信还是打电话?-----》发短信* 因为sendSms和call用的是synchronized关键字 锁的对象是方法的调用者* 两个方法是一个对象,用的同一把锁,谁先拿到谁先执行* @pojectname 线程相关*/
public class Test1 {public static void main(String[] args) throws InterruptedException {Phone phone = new Phone();new Thread(()->{phone.sendSms();},"A").start();TimeUnit.SECONDS.sleep(1);new Thread(()->{phone.call();},"B").start();}
}class Phone{public synchronized void sendSms(){try {TimeUnit.SECONDS.sleep(3);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("发短信snedSms");}public synchronized void call(){System.out.println("call");}
}
增加一个普通方法呢?
Phone2 phone = new Phone2();new Thread(()->{phone.sendSms();},"A").start();TimeUnit.SECONDS.sleep(1);new Thread(()->{phone.hello();},"B").start();
public void hello(){System.out.println("hello hello");
}
我们发现1S过后hello方法先执行
因为普通方法不受锁的影响
情况二
两个对象,两个同步方法
Phone2 phone1 = new Phone2();Phone2 phone2 = new Phone2();new Thread(()->{phone1.sendSms();},"A").start();TimeUnit.SECONDS.sleep(1);new Thread(()->{phone2.call();},"B").start();
class Phone2{public synchronized void sendSms(){try {TimeUnit.SECONDS.sleep(3);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("发短信snedSms");}public synchronized void call(){System.out.println("call");}
}
call先打印,这个时候就跟延迟有关了,因为锁的对象不一样,谁快先调用谁
情况三
方法变成静态同步方法(static修饰)
public class Test3 {public static void main(String[] args) throws InterruptedException {Phone3 phone = new Phone3();new Thread(()->{phone.sendSms();},"A").start();TimeUnit.SECONDS.sleep(1);new Thread(()->{phone.call();},"B").start();}
}class Phone3{public static synchronized void sendSms(){try {TimeUnit.SECONDS.sleep(3);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("发短信snedSms");}public static synchronized void call(){System.out.println("call");}
}
我们发现发短信先打印
原因:
**1.**synchronized关键字锁的对象是方法的调用者,同一个对象,谁先拿到谁执行
**2.**static : 静态方法 类一加载就有了 是一个Class 模板
Phone3只有唯一的一个class对象 -–-–> Class phone3Class = Phone3.class;,因此,我们这个地方锁的的class,全局唯一,用的肯定是同一个锁
如:
Phone3 phone1 = new Phone3();
Phone3 phone2 = new Phone3();
new Thread(()->{phone1.sendSms();},"A").start();
TimeUnit.SECONDS.sleep(1);
new Thread(()->{phone2.call();},"B").start();
还是发短信先打印,也就印证了我们的Static修饰的同步方法,锁的就是Class,一定是谁先拿到谁先执行
情况四
一个对象+静态同步方法+普通同步方法
public class Test4 {public static void main(String[] args) throws InterruptedException {Phone4 phone = new Phone4();new Thread(()->{phone.sendSms();},"A").start();TimeUnit.SECONDS.sleep(1);new Thread(()->{phone.call();},"B").start();}
}class Phone4{//静态同步方法public static synchronized void sendSms(){try {TimeUnit.SECONDS.sleep(3);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("发短信snedSms");}//普通同步方法public synchronized void call(){System.out.println("call");}
}
打电话先输出
原因:
锁的对象不同,前者锁的是Class类模板,后者锁的调用者
由于前者有延迟,锁对象不一样,后者不需要等解锁
两个对象+静态同步方法+普通同步方法
Phone4 phone = new Phone4();
Phone4 phone1 = new Phone4();
new Thread(()->{phone.sendSms();},"A").start();
TimeUnit.SECONDS.sleep(1);
new Thread(()->{phone1.call();},"B").start();
谁没有延迟(谁的低),谁先执行,
锁的对象不同,前者锁的是Class类模板,后者锁的调用者
由于前者有延迟,锁对象不一样,后者不需要等解锁
总结:
一个是new出来的对象 ,是一个具体的实例,可以多个同一类型的实例,那么锁就有可能不一样了
一个是Class类模板,锁的是这个类型的对象模板,Class模板全局唯一,锁的对象一定一样
五.集合类不安全
List不安全
代码
public class ListTest {public static void main(String[] args) {List<String> list = new ArrayList<>();for (int i = 0; i<10;i++){new Thread(()->{list.add(UUID.randomUUID().toString().substring(0,5));System.out.println(list);},String.valueOf(i)).start();}}
}
错误:
Exception in thread “0” Exception in thread “4” Exception in thread “2” java.util.ConcurrentModificationException
并发修改异常
我们发现并发下List是不安全的
解决方案
1.使用Vector<>()
List<String> list = new Vector<>();
为什么安全呢?
我们的Vector源码中,官方在添加元素的时候给我们写了synchronized修饰add方法(比ArrayList早出来)
public synchronized void addElement(E obj) {modCount++;ensureCapacityHelper(elementCount + 1);elementData[elementCount++] = obj;
}
2.List顶层老大Collections工具类
List<String> list = Collections.synchronizedList(new ArrayList<>());
把我们的List变成线程安全
3.CopyOnWriteArrayList
List<String> list = new CopyOnWriteArrayList<>();
//CopyOnWriteArrayList源码
public CopyOnWriteArrayList() {setArray(new Object[0]);
}
private transient volatile Object[] array;
CopyOnWrite 写入时赋值
COW计算机程序设计领域的一种优化策略
多个线程调用的时候,list,读取的时候是固定的,写入的时候(覆盖操作)在写入的时候避免覆盖,造成数据问题
优点:
我们的Vector的add方法是synchronized来修饰了,效率比较低
我们再来看看CopyOnWriteArrayList的add方法
public boolean add(E e) {final ReentrantLock lock = this.lock;lock.lock();try {Object[] elements = getArray();int len = elements.length;Object[] newElements = Arrays.copyOf(elements, len + 1);newElements[len] = e;setArray(newElements);return true;} finally {lock.unlock();}
}
我们可以看出,CopyOnWriteArrayList是用lock锁,效率高
Set不安全
代码:
public class SetTest {public static void main(String[] args) {HashSet<String> set = new HashSet<>();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();}}
}
同理错误类型为:java.util.ConcurrentModificationException
解决方案
1.Collections工具类
Set<String> set = Collections.synchronizedSet(new HashSet<>());
2.CopyOnWriteSet
Set<String> set = new CopyOnWriteArraySet<>();
HashSet底层源码
HashSet就是一个HashMap
public HashSet() {map = new HashMap<>();
}
//HashSet的add方法
//set本质就是map的key,key是唯一的,所以set是无序的
public boolean add(E e) {return map.put(e, PRESENT)==null;
}
private static final Object PRESENT = new Object();//常量
HashMap不安全
//map是这样用的么,
//默认等价于什么
Map<String,String> map = new HashMap<>();
Map<String,String> map = new HashMap<>(16,0.75);
Map源码
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 位运算16static final int MAXIMUM_CAPACITY = 1 << 30;static final float DEFAULT_LOAD_FACTOR = 0.75f;//默认加载因子//初始容量
public HashMap(int initialCapacity) {this(initialCapacity, DEFAULT_LOAD_FACTOR);
}/*** Constructs an empty <tt>HashMap</tt> with the default initial capacity* (16) and the default load factor (0.75).*/
//加载因子
public HashMap() {this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
代码
public class MapTest {public static void main(String[] args) {Map<String,String> map = new HashMap<>();for(int i=0;i<=60;i++){new Thread(()->{map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0,5));System.out.println(map);},String.valueOf(i)).start();}}
}
也会有并发修改错误
解决方案
1.Collections工具类
Map<String,String> map = Collections.synchronizedMap(new HashMap<>());
2.ConcurrentHashMap
Map<String,String> map = new ConcurrentHashMap<>();
//ConcurrentHashMap源码
public ConcurrentHashMap() {}
public ConcurrentHashMap(int initialCapacity) {if (initialCapacity < 0)throw new IllegalArgumentException();int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ?MAXIMUM_CAPACITY :tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1));this.sizeCtl = cap;}
六.Callable
1.可以有返回值
2.可以抛出异常
3.方法不同,run()/start
@FunctionalInterface
public interface Callable<V> {/*** Computes a result, or throws an exception if unable to do so.** @return computed result* @throws Exception if unable to compute a result*/V call() throws Exception;
}
函数式接口
我们发现函数泛型就是我们返回值的类型,泛型写那种类型,我们就返回那种类型
那么我们如何启动Callable呢?
我们看源码发现
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2dwA682L-1605609859700)(C:\Users\王庆华\AppData\Roaming\Typora\typora-user-images\image-20201114184939059.png)]
Thread的构造函数重载都是Runable类型
那么Callable怎么跟Thread搭上关系
package com.hkd.callable;import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;/*** @author 王庆华* @version 1.0* @date 2020/11/14 18:45* @Description TODO* @pojectname 线程相关*/
public class CallableTest {public static void main(String[] args) throws ExecutionException, InterruptedException {//怎么启动callable//new Thread(new Runnable()).start();// new Thread(new FutureTask<>(Callable)).start();;new Thread().start();MyThread myThread = new MyThread();FutureTask futureTask = new FutureTask(myThread);new Thread(futureTask,"A").start();new Thread(futureTask,"B").start();//结果会被缓存,效率高Object o = futureTask.get();System.out.println(o);}
}class MyThread implements Callable<String>{@Overridepublic String call() throws Exception {return "1234";}
}
细节:
1.有缓存的
2.结果可能需要等待,会阻塞
七.JUC常用的辅助类
1.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()+"走了");//倒计时完毕 减一countDownLatch.countDown();},String.valueOf(i)).start();}//等待计数器归零然后在向下执行countDownLatch.await();System.out.println("关门");}
}
原理:
countDownLatch.countDown(); :数量减一
countDownLatch.await();:等待计数器归零,然后在向下执行
每次有线程调用,他就会减一,当计数器为0的时候,await就会被唤醒,然后执行
2.CyclicBarrier
加法计数器
一个只是计数,一个是计数完,调用线程
public class CyclicBarrierTest {//集齐七颗龙珠,召唤龙珠//召唤龙珠的线程public static void main(String[] args) {CyclicBarrier cyclicBarrier =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 {cyclicBarrier.await();//等待} catch (InterruptedException e) {e.printStackTrace();} catch (BrokenBarrierException e) {e.printStackTrace();}}).start();}}
}
我们会在循环的时候不停的调用线程收集龙珠,直到7颗龙珠,也就是7个线程调用完,才会执行下面的操作
如果我们
new CyclicBarrier(8,()->{
System.out.println(“召唤神龙”);
});
然而我们的for还是7,那么他就会一直等待,收集满8个才会向下执行,这个时候就卡死到这了
3.Semaphore
Semaphore:信号量
6个汽车,三个车位 123进 456等 3走了可能4要进来
这个int可以理解为线程数量(停车位)
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 {semaphore.release();}},String.valueOf(i)).start();}}
}
原理:
**acquire()
JUC编程入门(高并发)相关推荐
- 《Java并发编程入门与高并发面试》or 《Java并发编程与高并发解决方案》笔记
<Java并发编程入门与高并发面试>or <Java并发编程与高并发解决方案>笔记 参考文章: (1)<Java并发编程入门与高并发面试>or <Java并发 ...
- 尚硅谷-互联网大厂高频重点面试题 (第2季)JUC多线程及高并发
本期内容包括 JUC多线程并发.JVM和GC等目前大厂笔试中会考.面试中会问.工作中会用的高频难点知识. 斩offer.拿高薪.跳槽神器,对标阿里P6的<尚硅谷_互联网大厂高频重点面试题(第2季 ...
- Java 高并发_JAVA并发编程与高并发解决方案 JAVA高并发项目实战课程 没有项目经验的朋友不要错过!...
JAVA并发编程与高并发解决方案 JAVA高并发项目实战课程 没有项目经验的朋友不要错过! 1.JPG (37.82 KB, 下载次数: 0) 2018-12-3 09:40 上传 2.JPG (28 ...
- JavaWeb 并发编程 与 高并发解决方案
在这里写写我学习到和自己所理解的 Java高并发编程和高并发解决方案.现在在各大互联网公司中,随着日益增长的互联网服务需求,高并发处理已经是一个非常常见的问题,在这篇文章里面我们重点讨论两个方面的问题 ...
- 01 - Java并发编程与高并发解决方案笔记-基础篇
01 - Java并发编程与高并发解决方案笔记-基础篇 基础篇很重要!很重要!很重要!!!一定要理解和认真思考. 01 - Java并发编程与高并发解决方案笔记-基础篇 1.课程准备 2.并发编程基础 ...
- libevent c++高并发网络编程_高并发编程学习(2)——线程通信详解
前序文章 高并发编程学习(1)--并发基础 - https://www.wmyskxz.com/2019/11/26/gao-bing-fa-bian-cheng-xue-xi-1-bing-fa-j ...
- 高并发编程_高并发编程系列:7大并发容器详解(附面试题和企业编程指南)...
不知道从什么时候起,在Java编程中,经常听到Java集合类,同步容器.并发容器,高并发编程成为当下程序员需要去了解掌握的技术之一,那么他们有哪些具体分类,以及各自之间的区别和优劣呢? 只有把这些梳理 ...
- 高并发编程_高并发编程系列:全面剖析Java并发编程之AQS的核心实现
在并发编程领域,AQS号称是并发同步组件的基石,很多并发同步组件都是基于AQS实现,所以想掌握好高并发编程,你需要掌握好AQS. 本篇主要通过对AQS的实现原理.数据模型.资源共享方式.获取锁的过程, ...
- java并发编程与高并发解决方案
知识点 线程安全,线程封闭,线程调度,同步容器,并发容器,AQS,J.U.C,等等 高并发解决思路与手段 扩容:水平扩容.垂直扩容 缓存:Redis.Memcache.GuavaCache等 队列:K ...
- Linux IO多路复用之epoll网络编程,高并发的使用例子 (含源码)
本章节是用基本的Linux基本函数加上epoll调用编写一个完整的服务器和客户端例子,可在Linux上运行,客户端和服务端的功能如下: 客户端从标准输入读入一行,发送到服务端 服务端从网络读取一行,然 ...
最新文章
- 淘金尖端领域:全球量子技术最新投资趋势
- 6.Mybatis中的动态Sql和Sql片段(Mybatis的一个核心)
- 小熊电器、九阳、苏泊尔们的“颜价比”被外卖小哥“打回原形”
- 爬虫基础, 乱码问题, jupyter, urllib, requests, lxml, multiprocessing并发, session, beautifulsoup...
- oracle的connect by语句
- Nhibernate 对view 查询的几种方法
- Linux系统间文件双向同步搭建Unison版
- 怎么取消计算机的用户名和密码怎么设置密码,开机密码如何取消 电脑开机密码取消设置方法介绍...
- 今日恐慌与贪婪指数为54 等级由贪婪转为中立
- sp根据备份文件来创建DB
- H3C交换机配置DHCP服务器
- Android: app不被系统kill掉
- Atitit enhance dev effect提升开发效率的十大原理与方法v2 u66.docx Atitit enhance dev effect提升开发效率的十大原理 目录 1. 管理	2
- 2060显卡驱动最新版本_堪比显卡界中的小米,价格屠夫,1999的铭瑄RTX2060终结者体验...
- kx linux驱动下载,创新5.1声卡驱动kX Project Audio DriverV5.1免费版下载 - 下载吧
- gc buffer busy acquire 、gc buffer busy release
- 减持奈飞增持京东健康,“贝莱德们”为何开始偏爱中国企业?
- 小试ESP8266(一) 一只电阻, 几条语句, 摆脱深度睡眠反复重启的困扰
- 搭建自动化测试平台(selenium+testng+maven+svn+Jenkins)【转自galen2016】
- 如何用计算机产生随机数,如何在计算器产生随机数
热门文章
- java doubke类型转换为String_Java的基本数据类型你知道吗?
- 免安装mysql5.7.22_windows环境下安装MySQL5.7.22免安装版
- TypeScript:函数进阶
- MyBatis学习笔记(3)-动态SQL
- tensorflow学习笔记(3)梯度下降法进行曲线拟合和线性回归
- 低照度图像修复方法总结
- 深度学习笔记(四)——ResNet模型学习与复现
- 最大矩形面积(C++实现)
- SVM支持向量机算法详解
- 实验三:从整理上理解进程创建、可执行文件的加载和进程执行进程切换,重点理解分析fork、execve和进程切换...