Java玩转高并发

    科技2022-08-19  97

    并行之美

    并行计算出于业务模型的需要–并不是为了提高系统性能,而是确实在业务上需要多个执行单元。–比如HTTP服务器,为每一个Socket连接新建一个处理线程–让不同线程承担不同的业务工作–简化任务调度

    同步(synchronous)和异步(asynchronous) 同步:存在两个时间点 异步:可一个时间点发生并发(Concurrency)和并行(Parallelism) 并发:一条路 并行:两条路临界区 临界区用来表示一种公共资源或者说是共享数据,可以被多个线程使用。但是每一次,只能有一个线程使用它,一旦临界区资源被占用,其他线程要想使用这个资源,就必须等待。阻塞(Blocking)和非阻塞(Non-Blocking) 阻塞和非阻塞通常用来形容多线程间的相互影响。比如一个线程占用了临界区资源,那么其它所有需要这个资源的线程就必须在这个临界区中进行等待,等待会导致线程挂起。这种情况就是阻塞。此时,如果占用资源的线程一直不愿意释放资源,那么其它所有阻塞在这个临界区上的线程都不能工作。 非阻塞允许多个线程同时进入临界区死锁(Deadlock)、饥饿(Starvation)和活锁(Livelock) 死锁:闭环 饥饿:是指某一个或者多个线程因为种种原因无法获得所需要的资源,导致一直无法执行 活锁:电梯遇人并行的级别 阻塞:当一个线程进入临界区后,其他线程必须等待 非阻塞:–无障碍–无锁–无等待 无障碍(Obstruction-Free)–无障碍是一种最弱的非阻塞调度–自由出入临界区–无竞争时,有限步内完成操作–有竞争时,回滚数据 无等待(Wait-Free)–无锁的–要求所有的线程都必须在有限步内完成–无饥饿的 无锁(Lock-Free)–是无障碍的–保证有一个线程可以胜出 while (!atomicVar.compareAndSet(localVar, localVar+1)) { localVar= atomicVar.get(); }

    并行基础

    什么是线程–线程是进程内的执行单元新建线程: Thread t1=new Thread(){ @Override public void run(){ System.out.println("Hello, I am t1"); } }; t1.start(); t1.run(); //不能开启线程

    终止线程–Thread.stop() 不推荐使用。它会释放所有monitor

    中断线程 public void Thread.interrupt() // 中断线程 public booleanThread.isInterrupted() // 判断是否被中断public static booleanThread.interrupted() // 判断是否被中断,并清除当前中断状态

    挂起(suspend)和继续执行(resume)线程 –suspend()不会释放锁 –如果加锁发生在resume()之前,则死锁发生

    等待线程结束(join)和谦让(yeild) public final void join() throws InterruptedException public final synchronized void join(long millis) throws InterruptedException join的本质while (isAlive()) {wait(0);} 线程执行完毕后,系统会调用notifyAll() 不要在Thread实例上使用wait()和notify()方法

    守护线程 在后台默默地完成一些系统性的服务,比如垃圾回收线程、JIT线程就可以理解为守护线程 当一个Java应用内,只有守护线程时,Java虚拟机就会自然退出

    线程优先级

    Thread high=new HightPriority(); LowPrioritylow=new LowPriority(); high.setPriority(Thread.MAX_PRIORITY); low.setPriority(Thread.MIN_PRIORITY); low.start(); high.start();//高优先级的线程更容易再竞争中获胜 线程同步( synchronized) –指定加锁对象:对给定对象加锁,进入同步代码前要获得给定对象的锁。 –直接作用于实例方法:相当于对当前实例加锁,进入同步代码前要获得当前实例的锁。 –直接作用于静态方法:相当于对当前类加锁,进入同步代码前要获得当前类的锁。Object.wait() Obejct.notify() [随机唤醒一个] 会释放锁 //指定加锁对象 public void run() { for(intj=0;j<10000000;j++){ synchronized(instance){ i++; } } } //用在方法上 public synchronized void increase(){ i++; } public static synchronizedvoid increase(){ i++; }

    Java内存模型

    原子性:是指一个操作是不可中断的。即使是在多个线程一起执行的时候,一个操作一旦开始,就不会被其它线程干扰。eg:i++不是原子操作有序性:在并发时,程序的执行可能就会出现乱序(导致原因:指令重排); tip:一条指令的执行是可以分为很多步骤的–取指IF–译码和取寄存器操作数ID–执行或者有效地址计算EX–存储器访问MEM–写回WB。可见性:是指当一个线程修改了某一个共享变量的值,其他线程是否能够立即知道这个修改。 –编译器优化 –硬件优化(如写吸收,批操作)Happen-Before规则: –程序顺序原则:一个线程内保证语义的串行性 eg:a=1;b=a+1; –volatile规则:volatile变量的写,先发生于读,这保证了volatile变量的可见性 –传递性:A先于B,B先于C,那么A必然先于C –线程的start()方法先于它的每一个动作 –线程的所有操作先于线程的终结(Thread.join()) –线程的中断(interrupt())先于被中断线程的代码 –对象的构造函数执行结束先于finalize()方法a=1;b=a+1;线程安全的概念:指某个函数、函数库在多线程环境中被调用时,能够正确地处理各个线程的局部变量,使程序功能正确完成. public class AccountingSyncimplements Runnable{ static AccountingSyncinstance=new AccountingSync(); static inti=0; @Override public void run() { for(intj=0;j<10000000;j++){ synchronized(instance){ i++; } } } }
    Processed: 0.017, SQL: 9