Java高并发编程详解_极悦注册
专注Java教育14年 全国咨询/投诉热线:444-1124-454
极悦LOGO图
始于2009,口口相传的Java黄埔军校
首页 学习攻略 Java学习 Java高并发编程详解

Java高并发编程详解

更新时间:2022-08-08 12:19:31 来源:极悦 浏览963次

Java教程中,高并发编程是一定要学习的,下面极悦小编来为大家进行介绍。

This Monitor和Class Monitor的详细介绍

synchronized同步类的不同实例方法,争抢的是同一个monitor的lock,而与之关联的引用是ThisMonitor的实例引用

package JavaConcurrencyInPractice.book.charpter3;
import java.util.concurrent.TimeUnit;
/**
 * @program: JavaLife
 * @author: JiaLe Hu
 * @create: 2020-12-09 10:38
 **/
public class ThisMonitor {
    public synchronized void method1() {
        System.out.println(Thread.currentThread().getName() + "enter to method1");
        try {
            TimeUnit.MINUTES.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public void method2() {
        synchronized (this) {
            System.out.println(Thread.currentThread().getName() + "enter to method1");
            try {
                TimeUnit.MINUTES.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
//    public synchronized void method2() {
//        System.out.println(Thread.currentThread().getName() + "enter to method2");
//        try {
//            TimeUnit.MINUTES.sleep(10);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
//    }
    public static void main(String[] args) {
        ThisMonitor thisMonitor = new ThisMonitor();
        new Thread(thisMonitor::method1, "T1").start();
        new Thread(thisMonitor::method2, "T2").start();
    }
}

synchronized同步某个类的不同静态方法争抢的锁也是同一个monitor的lock,该monitor关联的引用是ClassMonitor.class实例

package JavaConcurrencyInPractice.book.charpter3;
import java.util.concurrent.TimeUnit;
/**
 * @program: JavaLife
 * @author: JiaLe Hu
 * @create: 2020-12-09 10:49
 **/
public class ClassMonitor {
    public static synchronized void method1() {
        System.out.println(Thread.currentThread().getName() + "enter to method1");
        try {
            TimeUnit.MINUTES.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
//    public static synchronized void method2() {
//        System.out.println(Thread.currentThread().getName() + "enter to method1");
//        try {
//            TimeUnit.MINUTES.sleep(10);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
//    }
    public static synchronized void method2() {
        synchronized (ClassMonitor.class) {
            System.out.println(Thread.currentThread().getName() + "enter to method1");
            try {
                TimeUnit.MINUTES.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

重入

内置锁是可以重入的,如果某个线程试图获得一个已经由它自己持有的锁,那么这个请求就会成功。重入意味着获取锁的操作的粒度是线程。

Wait And notify

wait 方法是可中断的,当前线程一旦调用了wait方法进入阻塞状态,其他线程是可以使用interrupt方法将其打断。

线程执行了某个对象的wait方法,会加入与之对应的wait set中,每一个对象的monitor都有一个与之关联的wait set

必须在同步方法中使用wait和notify,因为执行wait和notify的前提条件是必须持有同步方法的monitor的所有权

wait会释放掉monitor的锁

synchronized 的缺陷

不能控制阻塞的时间

同步方法不能被中断,不能像wait和sleep方法一样,能够捕获得到中断信号

package LeetCode;
import java.util.concurrent.TimeUnit;
/**
 * @program: JavaLife
 * @author: JiaLe Hu
 * @create: 2020-12-10 09:32
 **/
public class synchronizedDefect {
    public synchronized void syncMethod() {
        try {
            System.out.println(Thread.currentThread().getName() + " get this monitor");
            TimeUnit.HOURS.sleep(1);
        } catch (InterruptedException e) {
            System.out.println(Thread.currentThread().getName() + " is interrupted");
        }
    }
    public static void main(String[] args) throws InterruptedException {
        synchronizedDefect synchronizedDefect = new synchronizedDefect();
        Thread t1 = new Thread(synchronizedDefect::syncMethod, "t1");
        t1.start();
        TimeUnit.MILLISECONDS.sleep(2);
        Thread t2 = new Thread(synchronizedDefect::syncMethod, "t2");
        t2.start();
        TimeUnit.MILLISECONDS.sleep(2);
        t2.interrupt();
        System.out.println(t2.isInterrupted()); // true
        System.out.println(t2.getState()); // BLOCKED
    }
}

Hook函数

该ThreadGroup如果有父ThreadGroup,则直接调用父Group的uncaughtException方法

如果设置了全局默认的UncaughtException,则会调用全局的uncaughtException方法

若既没有父ThreadGroup,也没有全局默认的UncaughtException,直接将异常的堆栈信息定向到System.err中

Hook注入(Runtime)

package JavaConcurrencyInPractice.book.charpter4;
import java.util.concurrent.TimeUnit;
/**
 * @program: JavaLife
 * @author: JiaLe Hu
 * @create: 2020-12-11 11:05
 **/
public class ThreadHook {
    public static void main(String[] args) {
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            try {
                System.out.println("The hook thread 1 is running ");
                TimeUnit.SECONDS.sleep(1);
                System.out.println("The hook thread 1 will exit");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }));
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            try {
                System.out.println("The hook thread 2 is running ");
                TimeUnit.SECONDS.sleep(2);
                System.out.println("The hook thread 2 will exit");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }));
        System.out.println("program is exiting");
    }
}

Hook线程应用场景以及注意事项

Hook线程只有在收到推出信号的时候会被执行,如果在kill的时候使用了参数-9,那么Hook线程不会执行,进程将立即退出,因此lock文件不会被删除

Hook线程中也可以执行一些资源释放的工作,比如关闭文件句柄、socket链接、数据库connection

尽量不要在Hook线程中执行一些耗时非常长的操作。因此会导致程序迟迟不能退出。

类加载的过程

使用new关键字会导致类的初始化

访问类的静态变量

访问类的静态方法,会导致类的初始化

对某个类进行反射

初始化子类会导致父类的初始化(通过子类的静态变量只会导致父类的初始化)

启动类

除了上述的6种情况,其余都被称为被动使用,不会导致类的加载和初始化

类的加载阶段

class文件种的二进制数据读取到内存中,然后将该字节流所代表的静态存储结构转换为方法区中的运行时的数据结构,并且在堆内存中生成一个该类的java.lang.Class对象,作为访问方法区数据结构的入口。加载过程常伴随着连接阶段交叉工作。

类初始化的阶段

包含了所有类变量的赋值动作和静态语句块的执行代码

静态语句块只能对后面的静态变量进行赋值,但是不能对其访问。父类的静态变量总是能够得到优先赋值。

JVM内置三大加载器

根加载器

根加载器又被称为Bootstrap类加载器,该类加载器是最为顶层的加载器,其没有父加载器,它是由C++编写的,主要负责虚拟机核心类库的加载-Xbootclasspath来指定根加载器的路径

扩展类加载器

扩展类加载器的父加载器是根加载器,主要用于加载JAVA_HOME下jre/lb/ext子目录里面的类库。由纯Java语言实现

系统类加载器

负责加载classpath下的类库资源

如果大家想了解更多相关知识,可以关注一下极悦的Java多线程并发编程,里面有更丰富的知识等着大家去学习,希望对大家能够有所帮助。

提交申请后,顾问老师会电话与您沟通安排学习

免费课程推荐 >>
技术文档推荐 >>