浅谈Java并发中ReentrantLock锁应该怎么用

目录
  • 1、重入锁
    • 说明
  • 2、中断响应
    • 说明
  • 3、锁申请等待限时
    • tryLock(long, TimeUnit)
    • tryLock()
  • 4、公平锁
    • 说明
  • 源码(JDK8)

重入锁可以替代关键字 synchronized 。

在 JDK5.0 的早期版本中,重入锁的性能远远优于关键字 synchronized ,

但从 JDK6.0 开始, JDK 在关键字 synchronized 上做了大量的优化,使得两者的性能差距并不大。

重入锁使用 ReentrantLock 实现

1、重入锁

package com.shockang.study.java.concurrent.lock;

import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockDemo implements Runnable {
    public static ReentrantLock lock = new ReentrantLock();
    public static int i = 0;

    @Override
    public void run() {
        for (int j = 0; j < 10000000; j++) {
            lock.lock();
            lock.lock();
            try {
                i++;
            } finally {
                lock.unlock();
                lock.unlock();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ReentrantLockDemo tl = new ReentrantLockDemo();
        Thread t1 = new Thread(tl);
        Thread t2 = new Thread(tl);
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(i);
    }
}

控制台打印

20000000

说明

一个线程连续两次获得同一把锁是允许的。

如果不允许这么操作,那么同一个线程在第 2 次获得锁时,将会和自己产生死锁。

程序就会“卡死”在第 2 次申请锁的过程中。

但需要注意的是,如果同一个线程多次获得锁,那么在释放锁的时候,也必须释放相同次数。

如果释放锁的次数多了,那么会得到一个 java.lang.IllegalMonitorStateException 异常,反之,如果释放锁的次数少了,那么相当于线程还持有这个锁,因此,其他线程也无法进入临界区。

2、中断响应

对于关键字 synchronized 来说,如果一个线程在等待锁,那么结果只有两种情况,要么它获得这把锁继续执行,要么它就保持等待。

而使用重入锁,则提供另外一种可能,那就是线程可以被中断。

也就是在等待锁的过程中,程序可以根据需要取消对锁的请求。

有些时候,这么做是非常有必要的。

比如,你和朋友约好一起去打球,如果你等了半个小时朋友还没有到,你突然接到一个电话,说由于突发情况,朋友不能如约前来了,那么你一定扫兴地打道回府了。

中断正是提供了一套类似的机制。

如果一个线程正在等待锁,那么它依然可以收到一个通知,被告知无须等待,可以停止工作了。

这种情况对于处理死锁是有一定帮助的。

下面的代码产生了一个死锁,但得益于锁中断,我们可以很轻易地解决这个死锁。

package com.shockang.study.java.concurrent.lock;

import java.util.concurrent.locks.ReentrantLock;

public class IntLock implements Runnable {
    public static ReentrantLock lock1 = new ReentrantLock();
    public static ReentrantLock lock2 = new ReentrantLock();
    int lock;

    /**
     * 控制加锁顺序,方便构造死锁
     *
     * @param lock
     */
    public IntLock(int lock) {
        this.lock = lock;
    }

    @Override
    public void run() {
        try {
            if (lock == 1) {
                lock1.lockInterruptibly();
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                }
                lock2.lockInterruptibly();
            } else {
                lock2.lockInterruptibly();
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                }
                lock1.lockInterruptibly();
            }

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (lock1.isHeldByCurrentThread())
                lock1.unlock();
            if (lock2.isHeldByCurrentThread())
                lock2.unlock();
            System.out.println(Thread.currentThread().getId() + ":线程退出");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        IntLock r1 = new IntLock(1);
        IntLock r2 = new IntLock(2);
        Thread t1 = new Thread(r1);
        Thread t2 = new Thread(r2);
        t1.start();
        t2.start();
        Thread.sleep(1000);
        //中断其中一个线程
        t2.interrupt();
    }
}

控制台输出

java.lang.InterruptedException

at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:898)

at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222)

at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)

at com.shockang.study.java.concurrent.lock.IntLock.run(IntLock.java:35)

at java.lang.Thread.run(Thread.java:748)

11:线程退出

12:线程退出

说明

线程 t1 和 t2 启动后, t1 先占用 lock1 ,再占用 lock2。

t2 先占用 lock2 ,再请求 lock1。

因此,很容易形成 t1 和 t2 之间的相互等待。

在这里,对锁的请求,统一使用 lockInterruptibly() 方法。

这是一个可以对中断进行响应的锁申请动作,即在等待锁的过程中,可以响应中断。

在代码第 56 行,主线程 main 处于休眠状态,此时,这两个线程处于死锁的状态。

在代码第 58 行,由于 t2 线程被中断,故 t2 会放弃对 lock1 的申请,同时释放已获得的 lock2 。

这个操作导致 t1 线程可以顺利得到 lock2 而继续执行下去。

3、锁申请等待限时

除了等待外部通知之外,要避免死锁还有另外一种方法,那就是限时等待。

依然以约朋友打球为例,如果朋友退退不来,又无法联系到他,那么在等待 1 到 2 个小时后,我想大部分人都会扫兴离去。

对线程来说也是这样。

通常,我们无法判断为什么一个线程退迟拿不到锁。

也许是因为死锁了,也许是因为产生了饥饿。

如果给定一个等待时间,让线程自动放弃,那么对系统来说是有意义的。

我们可以使用 tryLock() 方法进行一次限时的等待。

tryLock(long, TimeUnit)

下面这段代码展示了限时等待锁的使用。

package com.shockang.study.java.concurrent.lock;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

public class TimeLock implements Runnable {
    public static ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        try {
            if (lock.tryLock(5, TimeUnit.SECONDS)) {
                Thread.sleep(6000);
            } else {
                System.out.println("get lock failed");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        TimeLock tl = new TimeLock();
        Thread t1 = new Thread(tl);
        Thread t2 = new Thread(tl);
        t1.start();
        t2.start();
    }
}

控制台打印

get lock failed
Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:151)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1261)
at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:457)
at com.shockang.study.java.concurrent.lock.TimeLock.run(TimeLock.java:20)
at java.lang.Thread.run(Thread.java:748)

说明

在这里, tryLock() 方法接收两个参数,一个表示等待时长,另外一个表示计时单位。

这里的单位设置为秒,时长为 5 ,表示线程在这个锁请求中最多等待 5 秒。

如果超过 5 秒还没有得到锁,就会返回 false 。

如果成功获得锁,则返回 true 。

在本例中,由于占用锁的线程会持有锁长达 6 秒,故另一个线程无法在 5 秒的等待时间内获得锁,因此请求锁会失败。

tryLock()

ReentrantLock.tryLock() 方法也可以不带参数直接运行。

在这种情况下,当前线程会尝试获得锁,如果锁并未被其他线程占用,则申请锁会成功,并立即返回 true 。

如果锁被其他线程占用,则当前线程不会进行等待,而是立即返回 false 。

这种模式不会引起线程等待,因此也不会产生死锁。

package com.shockang.study.java.concurrent.lock;

import java.util.concurrent.locks.ReentrantLock;

public class TryLock implements Runnable {
    public static ReentrantLock lock1 = new ReentrantLock();
    public static ReentrantLock lock2 = new ReentrantLock();
    int lock;

    public TryLock(int lock) {
        this.lock = lock;
    }

    @Override
    public void run() {
        if (lock == 1) {
            while (true) {
                if (lock1.tryLock()) {
                    try {
                        try {
                            Thread.sleep(500);
                        } catch (InterruptedException e) {
                        }
                        if (lock2.tryLock()) {
                            try {
                                System.out.println(Thread.currentThread()
                                        .getId() + ":My Job done");
                                return;
                            } finally {
                                lock2.unlock();
                            }
                        }
                    } finally {
                        lock1.unlock();
                    }
                }
            }
        } else {
            while (true) {
                if (lock2.tryLock()) {
                    try {
                        try {
                            Thread.sleep(500);
                        } catch (InterruptedException e) {
                        }
                        if (lock1.tryLock()) {
                            try {
                                System.out.println(Thread.currentThread()
                                        .getId() + ":My Job done");
                                return;
                            } finally {
                                lock1.unlock();
                            }
                        }
                    } finally {
                        lock2.unlock();
                    }
                }
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        TryLock r1 = new TryLock(1);
        TryLock r2 = new TryLock(2);
        Thread t1 = new Thread(r1);
        Thread t2 = new Thread(r2);
        t1.start();
        t2.start();
    }
}

控制台输出

11:My Job done
12:My Job done

说明

上述代码采用了非常容易死锁的加锁顺序。

也就是先让 t1 获得 lock1 ,再让 2 获得 lock2 ,接着做反向请求,让 t1 申请 lock2 , t2 申请 lock1 。

在一般情况下,这会导致 t1 和 2 相互等待。

待,从而引起死锁。

但是使用 tryLock() 方法后,这种情况就大大改善了。

由于线程不会傻傻地等待,而是不停地尝试,因此,只要执行足够长的时间,线程总是会得到所有需要的资源,从而正常执行(这里以线程同时获得 lock1 和 lock2 两把锁,作为其可以正常执行的条件)。

在同时获得 lock1 和 lock2 后,线程就打印出标志着任务完成的信息“ My Job done”。

4、公平锁

在大多数情况下,锁的申请都是非公平的。

也就是说,线程 1 首先请求了锁 A ,接着线程 2 也请求了锁 A 。

那么当锁 A 可用时,是线程 1 可以获得锁还是线程 2 可以获得锁呢?

这是不一定的,系统只是会从这个锁的等待队列中随机挑选一个。

因此不能保证其公平性。

这就好比买票不排队,大家都围在售票窗口前,售票员忙得焦头烂额,也顾不及谁先谁后,随便找个人出票就完事了。

而公平的锁,则不是这样,它会按照时间的先后顺序,保证先到者先得,后到者后得。

公平锁的一大特点是:它不会产生饥饿现象。

关于线程饥饿请参考我的博客——死锁、活锁和饥饿是什么意思?

只要你排队,最终还是可以等到资源的。

如果我们使用 synchronized 关键字进行锁控制,那么产生的锁就是非公平的。

而重入锁允许我们对其公平性进行设置。

它的构造函数如下:

/**
 * 使用给定的公平策略创建一个 ReentrantLock 的实例。
 *
 * @param fair 如果此锁应使用公平排序策略为 true
 */
public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}

当参数 fair 为 true 时,表示锁是公平的。

公平锁看起来很优美,但是要实现公平锁必然要求系统维护一个有序队列,因此公平锁的实现成本比较高,性能却非常低下,因此,在默认情况下,锁是非公平的。

如果没有特别的需求,则不需要使用公平锁。

公平锁和非公平锁在线程调度表现上也是非常不一样的。

下面的代码可以很好地突出公平锁的特点。

package com.shockang.study.java.concurrent.lock;

import java.util.concurrent.locks.ReentrantLock;

public class FairLock implements Runnable {
    public static ReentrantLock fairLock = new ReentrantLock(true);

    @Override
    public void run() {
        while (true) {
            try {
                fairLock.lock();
                System.out.println(Thread.currentThread().getName() + " 获得锁");
            } finally {
                fairLock.unlock();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        FairLock r1 = new FairLock();
        Thread t1 = new Thread(r1, "Thread_t1");
        Thread t2 = new Thread(r1, "Thread_t2");
        t1.start();
        t2.start();
    }
}

控制台输出

获得锁

Thread_t2 获得锁

Thread_t2 获得锁

Thread_t2 获得锁

Thread_t2 获得锁

Thread_t1 获得锁

Thread_t1 获得锁

Thread_t2 获得锁

Thread_t2 获得锁

Thread_t2 获得锁

Thread_t1 获得锁

Thread_t1 获得锁

# 省略

说明

由于代码会产生大量输出,这里只截取部分进行说明。

在这个输出中,很明显可以看到,两个线程基本上是交替获得锁的,几乎不会发生同一个线程连续多次获得锁的可能,从而保证了公平性。

如果设置了 false,则会根据系统的调度,一个线程会倾向于再次获取已经持有的锁,这种分配方式是高效的,但是无公平性可言。

源码(JDK8)

/**
 * 一种可重入互斥锁,其基本行为和语义与使用同步方法和语句访问的隐式监视锁(即 synchronized)相同,但具有扩展功能。
 *
 * 可重入锁属于上次成功锁定但尚未解锁它的线程。
 *
 * 当锁不属于另一个线程时,调用锁的线程将返回,并成功获取锁。
 *
 * 如果当前线程已经拥有锁,则该方法将立即返回。这可以使用 isHeldByCurrentThread 和 getHoldCount 方法进行检查。
 *
 * 此类的构造函数接受可选的公平性参数。
 *
 * 当设置为 true 时,在竞争状态下,锁有利于向等待时间最长的线程授予访问权限。否则,此锁不保证任何特定的访问顺序。
 *
 * 使用由多线程访问的公平锁的程序可能显示较低的总吞吐量
 *
 * (即,较慢;通常比使用默认设置的要慢得多,但是在获得锁和保证不饥饿的时间上有较小的差异。
 *
 * 但是请注意,锁的公平性并不能保证线程调度的公平性。
 *
 * 因此,使用公平锁的多个线程中的一个线程可以连续多次获得公平锁,而其他活动线程则没有进行并且当前没有持有该锁。
 *
 * 还要注意,untimed tryLock() 方法不支持公平性设置。
 *
 * 如果锁可用,即使其他线程正在等待,它也会成功。
 *
 * 建议的做法是总是在调用之后立即使用try块锁定,最典型的是在构建之前/之后,例如:
 *
 * class X {
 *   private final ReentrantLock lock = new ReentrantLock();
 *   // ...
 *
 *   public void m() {
 *     lock.lock();  // block until condition holds
 *     try {
 *       // ... method body
 *     } finally {
 *       lock.unlock()
 *     }
 *   }
 * }}
 *
 * 除了实现锁接口之外,这个类还定义了许多公共和受保护的方法来检查锁的状态。
 *
 * 其中一些方法只对 instrumentation 和 monitoring 有用。
 *
 * 此类的序列化与内置锁的行为相同:反序列化的锁处于未锁定状态,而与序列化时的状态无关。
 *
 * 此锁最多支持同一线程的2147483647个递归锁。尝试超过此限制会导致锁定方法抛出错误。
 *
 * @since 1.5
 * @author Doug Lea
 */
public class ReentrantLock implements Lock, java.io.Serializable 

到此这篇关于浅谈Java并发中ReentrantLock锁应该怎么用的文章就介绍到这了,更多相关ReentrantLock锁内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 深入理解java内置锁(synchronized)和显式锁(ReentrantLock)

    synchronized 和 Reentrantlock 多线程编程中,当代码需要同步时我们会用到锁.Java为我们提供了内置锁(synchronized)和显式锁(ReentrantLock)两种同步方式.显式锁是JDK1.5引入的,这两种锁有什么异同呢?是仅仅增加了一种选择还是另有其因?本文为您一探究竟. // synchronized关键字用法示例 public synchronized void add(int t){// 同步方法 this.v += t; } public stati

  • 详解Java中的ReentrantLock锁

    ReentrantLock锁 ReentrantLock是Java中常用的锁,属于乐观锁类型,多线程并发情况下.能保证共享数据安全性,线程间有序性 ReentrantLock通过原子操作和阻塞实现锁原理,一般使用lock获取锁,unlock释放锁, 下面说一下锁的基本使用和底层基本实现原理,lock和unlock底层 lock的时候可能被其他线程获得所,那么此线程会阻塞自己,关键原理底层用到Unsafe类的API: CAS和park 使用 java.util.concurrent.locks.R

  • ReentrantLock源码详解--公平锁、非公平锁

    问题 (1)重入锁是什么? (2)ReentrantLock如何实现重入锁? (3)ReentrantLock为什么默认是非公平模式? (4)ReentrantLock除了可重入还有哪些特性? 简介 Reentrant = Re + entrant,Re是重复.又.再的意思,entrant是enter的名词或者形容词形式,翻译为进入者或者可进入的,所以Reentrant翻译为可重复进入的.可再次进入的,因此ReentrantLock翻译为重入锁或者再入锁. 重入锁,是指一个线程获取锁之后再尝试获

  • Java中的显示锁ReentrantLock使用与原理详解

    考虑一个场景,轮流打印0-100以内的技术和偶数.通过使用 synchronize 的 wait,notify机制就可以实现,核心思路如下: 使用两个线程,一个打印奇数,一个打印偶数.这两个线程会共享一个数据,数据每次自增,当打印奇数的线程发现当前要打印的数字不是奇数时,执行等待,否则打印奇数,并将数字自增1,对于打印偶数的线程也是如此 //打印奇数的线程 private static class OldRunner implements Runnable{ private MyNumber n

  • ReentrantLock源码详解--条件锁

    问题 (1)条件锁是什么? (2)条件锁适用于什么场景? (3)条件锁的await()是在其它线程signal()的时候唤醒的吗? 简介 条件锁,是指在获取锁之后发现当前业务场景自己无法处理,而需要等待某个条件的出现才可以继续处理时使用的一种锁. 比如,在阻塞队列中,当队列中没有元素的时候是无法弹出一个元素的,这时候就需要阻塞在条件notEmpty上,等待其它线程往里面放入一个元素后,唤醒这个条件notEmpty,当前线程才可以继续去做"弹出一个元素"的行为. 注意,这里的条件,必须是

  • Java多线程 ReentrantLock互斥锁详解

    加锁和解锁 我们来看下ReentrantLock的基本用法 ThreadDomain35类 public class ThreadDomain35 { private Lock lock = new ReentrantLock(); public void testMethod() { try { lock.lock(); for (int i = 0; i < 2; i++) { System.out.println("ThreadName = " + Thread.curre

  • java高并发的ReentrantLock重入锁

    目录 synchronized的局限性 ReentrantLock ReentrantLock基本使用 ReentrantLock是可重入锁 ReentrantLock实现公平锁 ReentrantLock获取锁的过程是可中断的 tryLock无参方法 tryLock有参方法 ReentrantLock其他常用的方法 获取锁的4种方法对比 总结 synchronized的局限性 synchronized是java内置的关键字,它提供了一种独占的加锁方式.synchronized的获取和释放锁由j

  • Java并发编程之ReentrantLock可重入锁的实例代码

    目录 1.ReentrantLock可重入锁概述2.可重入3.可打断4.锁超时5.公平锁6.条件变量 Condition 1.ReentrantLock可重入锁概述 相对于 synchronized 它具备如下特点 可中断 synchronized锁加上去不能中断,a线程应用锁,b线程不能取消掉它 可以设置超时时间 synchronized它去获取锁时,如果对方持有锁,那么它就会进入entryList一直等待下去.而可重入锁可以设置超时时间,规定时间内如果获取不到锁,就放弃锁 可以设置为公平锁

  • 浅谈Java并发中ReentrantLock锁应该怎么用

    目录 1.重入锁 说明 2.中断响应 说明 3.锁申请等待限时 tryLock(long, TimeUnit) tryLock() 4.公平锁 说明 源码(JDK8) 重入锁可以替代关键字 synchronized . 在 JDK5.0 的早期版本中,重入锁的性能远远优于关键字 synchronized , 但从 JDK6.0 开始, JDK 在关键字 synchronized 上做了大量的优化,使得两者的性能差距并不大. 重入锁使用 ReentrantLock 实现 1.重入锁 package

  • 浅谈Java并发中的内存模型

    什么是JavaMemoryModel(JMM)? JMM通过构建一个统一的内存模型来屏蔽掉不同硬件平台和不同操作系统之间的差异,让Java开发者无需关注不同平台之间的差异,达到一次编译,随处运行的目的,这也正是Java的设计目的之一. CPU和内存 在讲JMM之前,我想先和大家聊聊硬件层面的东西.大家应该都知道执行运算操作的CPU本身是不具备存储能力的,它只负责根据指令对传递进来的数据做相应的运算,而数据存储这一任务则交给内存去完成.虽然内存的运行速度虽然比起硬盘快非常多,但是和3GHZ,4GH

  • 浅谈Java并发编程之Lock锁和条件变量

    简单使用Lock锁 Java 5中引入了新的锁机制--java.util.concurrent.locks中的显式的互斥锁:Lock接口,它提供了比synchronized更加广泛的锁定操作.Lock接口有3个实现它的类:ReentrantLock.ReetrantReadWriteLock.ReadLock和ReetrantReadWriteLock.WriteLock,即重入锁.读锁和写锁.lock必须被显式地创建.锁定和释放,为了可以使用更多的功能,一般用ReentrantLock为其实例

  • 浅谈JAVA并发之ReentrantLock

    1. 介绍 结合上面的ReentrantLock类图,ReentrantLock实现了Lock接口,它的内部类Sync继承自AQS,绝大部分使用AQS的子类需要自定义的方法存在Sync中.而ReentrantLock有公平与非公平的区别,即'是否先阻塞就先获取资源',它的主要实现就是FairSync与NonfairSync,后面会从源码角度看看它们的区别. 2. 源码剖析 Sync是ReentrantLock控制同步的基础.它的子类分为了公平与非公平.使用AQS的state代表获取锁的数量 ab

  • 浅谈java Collection中的排序问题

    这里讨论list.set.map的排序,包括按照map的value进行排序. 1)list排序 list排序可以直接采用Collections的sort方法,也可以使用Arrays的sort方法,归根结底Collections就是调用Arrays的sort方法. public static <T> void sort(List<T> list, Comparator<? super T> c) { Object[] a = list.toArray(); Arrays.

  • 浅谈java web中常用对象对应的实例化接口

    1. request对象 是javax.servlet.HttpServletRequest接口的实例化 2. response对象 是javax.servlet.HttpServletResponse接口的实例化 3. session 对象 是javax.servlet.HttpSession接口的实例化 4. application对象 是javax.servlet.ServletContext接口的实例化 以上是常用的对象 5. pageContext对象 是javax.servlet.j

  • 浅谈java线程中生产者与消费者的问题

    一.概念 生产者与消费者问题是一个金典的多线程协作的问题.生产者负责生产产品,并将产品存放到仓库:消费者从仓库中获取产品并消费.当仓库满时,生产者必须停止生产,直到仓库有位置存放产品:当仓库空时,消费者必须停止消费,直到仓库中有产品. 解决生产者/消费者问题主要用到如下几个技术:1.用线程模拟生产者,在run方法中不断地往仓库中存放产品.2.用线程模拟消费者,在run方法中不断地从仓库中获取产品.3  . 仓库类保存产品,当产品数量为0时,调用wait方法,使得当前消费者线程进入等待状态,当有新

  • 浅谈java继承中是否创建父类对象

    1. 调用父类构造方法是真的,但是根本没有创建父类对象,只不过是调用父类构造方法来初始化属性. 如果说调用父类构造方法就等于创建父类对象,那就真的无稽之谈. new指令开辟空间,用于存放对象的各个属/性引用等,反编译字节码你会发现只有一个new指令,所以开辟的是一块空间,一块空间就放一个对象. 然后,子类调用父类的属性,方法啥的,那并不是一个实例化的对象. 在字节码中子类会有个u2类型的父类索引,属于CONSTANT_Class_info类型,通过CONSTANT_Class_info的描述可以

  • 浅谈Java 类中各成分加载顺序和内存中的存放位置

    一.什么时候会加载类? 使用到类中的内容时加载:有三种情况 1.创建对象:new StaticCode(); 2.使用类中的静态成员:StaticCode.num=9;  StaticCode.show(); 3.在命令行中运行:java StaticCodeDemo 二.类所有内容加载顺序和内存中的存放位置 利用语句进行分析: 1.Person p=new Person("zhangsan",20); 该句话所做的事情: 1.在栈内存中,开辟main函数的空间,建立main函数的变量

  • 浅谈Java编程中string的理解与运用

    一,"=="与equals() 运行以下代码,如何解释其输出结果? public class StringPool { public static void main(String args[]) { String s0="Hello"; String s1="Hello"; String s2="He"+"llo"; System.out.println(s0==s1);//true System.out

随机推荐