찾다
Javajava지도 시간Java 직렬화 및 역직렬화에 대한 심층 분석

이 기사는 직렬화 및 역직렬화에 대한 관련 내용을 주로 소개하는 java에 대한 관련 지식을 제공합니다. 직렬화는 객체 지속성의 수단입니다. 모두에게 도움이 되기를 바랍니다.

Java 직렬화 및 역직렬화에 대한 심층 분석

추천 학습: "java 비디오 튜토리얼"

Java 객체 직렬화

Java 플랫폼을 사용하면 메모리에 재사용 가능한 Java 객체를 생성할 수 있지만 일반적으로 JVM이 실행 중일 때만 이러한 객체가 존재할 수 있습니다. 즉, 이러한 객체의 수명 주기는 JVM의 수명 주기보다 길지 않습니다. 그러나 실제 애플리케이션에서는 JVM 실행이 중지된 후 지정된 객체를 저장(지속)하고 나중에 저장된 객체를 다시 읽어야 할 수도 있습니다. Java 객체 직렬화는 이 기능을 달성하는 데 도움이 될 수 있습니다.

Java 객체 직렬화를 사용하면 객체를 저장할 때 해당 상태가 바이트 집합으로 저장되며 나중에 이러한 바이트가 객체로 결합됩니다. 객체 직렬화는 객체의 "상태", 즉 해당 멤버 변수를 저장한다는 점에 유의해야 합니다. 객체 직렬화는 클래스의 정적 변수에 주의를 기울이지 않는다는 것을 알 수 있습니다.

객체를 유지할 때 사용되는 객체 직렬화 외에도 RMI(원격 메서드 호출)를 사용하거나 네트워크를 통해 객체를 전송할 때도 객체 직렬화가 사용됩니다. Java 직렬화 API는 객체 직렬화를 처리하기 위한 표준 메커니즘을 제공합니다. API는 간단하고 사용하기 쉽습니다.

Java 객체를 직렬화 및 역직렬화하는 방법

Java에서는 클래스가 java.io.Serialized 인터페이스를 구현하는 한 직렬화할 수 있습니다. 다음은 코드입니다. java.io.Serializable接口,那么它就可以被序列化。这里先来一段代码:

code 1 创建一个User类,用于序列化及反序列化

package com.hollis;import java.io.Serializable;import java.util.Date;/**
 * Created by hollis on 16/2/2.
 */public class User implements Serializable{    private String name;    private int age;    private Date birthday;    private transient String gender;    private static final long serialVersionUID = -6849794470754667710L;    public String getName() {        return name;
    }    public void setName(String name) {        this.name = name;
    }    public int getAge() {        return age;
    }    public void setAge(int age) {        this.age = age;
    }    public Date getBirthday() {        return birthday;
    }    public void setBirthday(Date birthday) {        this.birthday = birthday;
    }    public String getGender() {        return gender;
    }    public void setGender(String gender) {        this.gender = gender;
    }    @Override
    public String toString() {        return "User{" +                "name='" + name + ''' +
                ", age=" + age +
                ", gender=" + gender +
                ", birthday=" + birthday +
                '}';
    }
}

code 2 对User进行序列化及反序列化的Demo

package com.hollis;import org.apache.commons.io.FileUtils;import org.apache.commons.io.IOUtils;import java.io.*;import java.util.Date;/**
 * Created by hollis on 16/2/2.
 */
public class SerializableDemo {

    public static void main(String[] args) {
        //Initializes The Object
        User user = new User();
        user.setName("hollis");
        user.setGender("male");
        user.setAge(23);
        user.setBirthday(new Date());
        System.out.println(user);

        //Write Obj to File
        ObjectOutputStream oos = null;
        try {            oos = new ObjectOutputStream(new FileOutputStream("tempFile"));
            oos.writeObject(user);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            IOUtils.closeQuietly(oos);
        }

        //Read Obj from File
        File file = new File("tempFile");
        ObjectInputStream ois = null;
        try {            ois = new ObjectInputStream(new FileInputStream(file));
            User newUser = (User) ois.readObject();
            System.out.println(newUser);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            IOUtils.closeQuietly(ois);
            try {
                FileUtils.forceDelete(file);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}
//output 
//User{name='hollis', age=23, gender=male, birthday=Tue Feb 02 17:37:38 CST 2016}
//User{name='hollis', age=23, gender=null, birthday=Tue Feb 02 17:37:38 CST 2016}

序列化及反序列化相关知识

1、在Java中,只要一个类实现了java.io.Serializable接口,那么它就可以被序列化。

2、通过ObjectOutputStreamObjectInputStream对对象进行序列化及反序列化

3、虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个类的序列化 ID 是否一致(就是 private static final long serialVersionUID

4、序列化并不保存静态变量。

5、要想将父类对象也序列化,就需要让父类也实现Serializable 接口。

6、Transient 关键字的作用是控制变量的序列化,在变量声明前加上该关键字,可以阻止该变量被序列化到文件中,在被反序列化后,transient 变量的值被设为初始值,如 int 型的是 0,对象型的是 null。

7、服务器端给客户端发送序列化对象数据,对象中有一些数据是敏感的,比如密码字符串等,希望对该密码字段在序列化时,进行加密,而客户端如果拥有解密的密钥,只有在客户端进行反序列化时,才可以对密码进行读取,这样可以一定程度保证序列化对象的数据安全。

ArrayList的序列化

在介绍ArrayList序列化之前,先来考虑一个问题:

如何自定义的序列化和反序列化策略

带着这个问题,我们来看java.util.ArrayList的源码

code 3

public class ArrayList<e> extends AbstractList<e>
        implements List<e>, RandomAccess, Cloneable, java.io.Serializable{    private static final long serialVersionUID = 8683452581122892189L;
    transient Object[] elementData; // non-private to simplify nested class access
    private int size;
}</e></e></e>

笔者省略了其他成员变量,从上面的代码中可以知道ArrayList实现了java.io.Serializable接口,那么我们就可以对它进行序列化及反序列化。因为elementData是transient的,所以我们认为这个成员变量不会被序列化而保留下来。我们写一个Demo,验证一下我们的想法:

code 4

public static void main(String[] args) throws IOException, ClassNotFoundException {
        List<string> stringList = new ArrayList<string>();
        stringList.add("hello");
        stringList.add("world");
        stringList.add("hollis");
        stringList.add("chuang");
        System.out.println("init StringList" + stringList);
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("stringlist"));
        objectOutputStream.writeObject(stringList);

        IOUtils.close(objectOutputStream);
        File file = new File("stringlist");
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(file));
        List<string> newStringList = (List<string>)objectInputStream.readObject();
        IOUtils.close(objectInputStream);
        if(file.exists()){
            file.delete();
        }
        System.out.println("new StringList" + newStringList);
    }
//init StringList[hello, world, hollis, chuang]//new StringList[hello, world, hollis, chuang]</string></string></string></string>

了解ArrayList的人都知道,ArrayList底层是通过数组实现的。那么数组elementData其实就是用来保存列表中的元素的。通过该属性的声明方式我们知道,他是无法通过序列化持久化下来的。那么为什么code 4的结果却通过序列化和反序列化把List中的元素保留下来了呢?

writeObject和readObject方法

在ArrayList中定义了来个方法: writeObjectreadObject

code 1 직렬화 및 역직렬화를 위한 User 클래스 생성

private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        elementData = EMPTY_ELEMENTDATA;        // Read in size, and any hidden stuff
        s.defaultReadObject();        // Read in capacity
        s.readInt(); // ignored

        if (size > 0) {            // be like clone(), allocate array based upon size not capacity
            ensureCapacityInternal(size);            Object[] a = elementData;            // Read in all elements in the proper order.
            for (int i=0; i<size>code 2 User 직렬화 및 역직렬화를 위한 데모<p></p>
<pre class="brush:php;toolbar:false">private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException{        // Write out element count, and any hidden stuff
        int expectedModCount = modCount;
        s.defaultWriteObject();        // Write out size as capacity for behavioural compatibility with clone()
        s.writeInt(size);        // Write out all elements in the proper order.
        for (int i=0; i<size><h2 id="직렬화-및-역직렬화-관련-지식">직렬화 및 역직렬화 관련 지식 </h2>
<p>1. Java에서는 클래스가 <code>java.io.Serialized</code> 인터페이스를 구현하는 한 직렬화될 수 있습니다. </p>🎜2. <code>ObjectOutputStream</code> 및 <code>ObjectInputStream</code>을 통해 객체를 직렬화 및 역직렬화합니다. 🎜🎜3. 가상 머신이 역직렬화를 허용하는지 여부는 클래스 경로 및 함수에만 의존하는 것이 아닙니다. , 매우 중요한 점은 두 클래스의 직렬화 ID가 일치하는지 여부입니다(즉, <code>private static final long serialVersionUID</code>) 🎜🎜4. 직렬화는 정적 변수를 저장하지 않습니다. 🎜🎜5. 상위 클래스 객체를 직렬화하려면 상위 클래스도 <code>Serialized</code> 인터페이스를 구현하도록 해야 합니다. 🎜🎜6. Transient 키워드의 기능은 변수 선언 전에 이 키워드를 추가하면 변수가 역직렬화된 후 임시 변수의 값이 설정되는 것을 방지할 수 있습니다. int 유형의 경우 0, 객체 유형의 경우 null과 같은 초기 값입니다. 🎜🎜7. 서버는 직렬화된 개체 데이터를 클라이언트에 보냅니다. 개체의 일부 데이터(예: 비밀번호 문자열 등)는 직렬화 중에 비밀번호 필드가 암호화되기를 바라며 클라이언트가 암호를 해독한 경우 비밀번호는 클라이언트가 키를 역직렬화할 때만 읽을 수 있으므로 직렬화된 개체의 데이터 보안을 어느 정도 보장할 수 있습니다. 🎜<h2 data-id="heading-3">ArrayList 직렬화🎜🎜ArrayList 직렬화를 소개하기 전에 다음 질문을 고려해 보겠습니다. 🎜🎜🎜직렬화 및 역직렬화 전략을 사용자 정의하는 방법🎜🎜🎜이 문제를 염두에 두고 <code>java.util.ArrayList</code>의 소스 코드를 보면🎜🎜code 3🎜<pre class="brush:php;toolbar:false">void invokeWriteObject(Object obj, ObjectOutputStream out)
        throws IOException, UnsupportedOperationException
    {        if (writeObjectMethod != null) {            try {
                writeObjectMethod.invoke(obj, new Object[]{ out });
            } catch (InvocationTargetException ex) {                Throwable th = ex.getTargetException();                if (th instanceof IOException) {                    throw (IOException) th;
                } else {
                    throwMiscException(th);
                }
            } catch (IllegalAccessException ex) {                // should not occur, as access checks have been suppressed
                throw new InternalError(ex);
            }
        } else {            throw new UnsupportedOperationException();
        }
    }
🎜작성자가 다른 멤버 변수를 생략했다는 것을 위의 코드에서 알 수 있듯이 ArrayList는 java를 구현합니다. io.Serialized인터페이스를 사용하면 직렬화 및 역직렬화할 수 있습니다. elementData는 일시적이기 때문에 이 멤버 변수는 직렬화되거나 유지되지 않을 것이라고 생각합니다. 아이디어를 검증하기 위해 데모를 작성해 보겠습니다. 🎜🎜code 4🎜
public interface Serializable {
}
🎜 ArrayList를 아는 사람이라면 ArrayList의 맨 아래 레이어가 배열을 통해 구현된다는 것을 알고 있습니다. 그런 다음 elementData 배열이 실제로 목록의 요소를 저장하는 데 사용됩니다. 우리는 이 속성이 선언되는 방식을 통해 직렬화를 통해 지속될 수 없다는 것을 알고 있습니다. 그렇다면 코드 4의 결과가 직렬화 및 역직렬화를 통해 목록의 요소를 유지하는 이유는 무엇입니까? 🎜

writeObject 및 readObject 메서드

🎜ArrayList에는 writeObjectreadObject라는 두 가지 메서드가 정의되어 있습니다. 🎜🎜결론은 다음과 같습니다. 🎜🎜직렬화 프로세스 중에 writeObject 및 readObject 메서드가 직렬화된 클래스에 정의되어 있으면 가상 머신은 개체 클래스의 writeObject 및 readObject 메서드를 호출하여 사용자 정의 직렬화를 수행하고 역직렬화. 🎜🎜해당 메소드가 없는 경우 기본 호출은 ObjectOutputStream의 defaultWriteObject 메소드와 ObjectInputStream의 defaultReadObject 메소드입니다. 🎜

用户自定义的 writeObject 和 readObject 方法可以允许用户控制序列化的过程,比如可以在序列化的过程中动态改变序列化的数值。

来看一下这两个方法的具体实现:

code 5

private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        elementData = EMPTY_ELEMENTDATA;        // Read in size, and any hidden stuff
        s.defaultReadObject();        // Read in capacity
        s.readInt(); // ignored

        if (size > 0) {            // be like clone(), allocate array based upon size not capacity
            ensureCapacityInternal(size);            Object[] a = elementData;            // Read in all elements in the proper order.
            for (int i=0; i<size><p>code 6</p>
<pre class="brush:php;toolbar:false">private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException{        // Write out element count, and any hidden stuff
        int expectedModCount = modCount;
        s.defaultWriteObject();        // Write out size as capacity for behavioural compatibility with clone()
        s.writeInt(size);        // Write out all elements in the proper order.
        for (int i=0; i<size><p>那么为什么ArrayList要用这种方式来实现序列化呢?</p>
<h3 id="strong-why-transient-strong"><strong>why transient</strong></h3>
<p>ArrayList实际上是动态数组,每次在放满以后自动增长设定的长度值,如果数组自动增长长度设为100,而实际只放了一个元素,那就会序列化99个null元素。为了保证在序列化的时候不会将这么多null同时进行序列化,ArrayList把元素数组设置为transient。</p>
<h3 id="strong-why-writeObject-and-readObject-strong"><strong>why writeObject and readObject</strong></h3>
<p>前面说过,为了防止一个包含大量空对象的数组被序列化,为了优化存储,所以,ArrayList使用<code>transient</code>来声明<code>elementData</code>。 但是,作为一个集合,在序列化过程中还必须保证其中的元素可以被持久化下来,所以,通过重写<code>writeObject</code> 和 <code>readObject</code>方法的方式把其中的元素保留下来。</p>
<p><code>writeObject</code>方法把<code>elementData</code>数组中的元素遍历的保存到输出流(ObjectOutputStream)中。</p>
<p><code>readObject</code>方法从输入流(ObjectInputStream)中读出对象并保存赋值到<code>elementData</code>数组中。</p>
<p>至此,我们先试着来回答刚刚提出的问题:</p>
<p>如何自定义的序列化和反序列化策略</p>
<p>答:可以通过在被序列化的类中增加writeObject 和 readObject方法。那么问题又来了:</p>
<p>虽然ArrayList中写了writeObject 和 readObject 方法,但是这两个方法并没有显示的被调用啊。</p>
<p><strong>那么如果一个类中包含writeObject 和 readObject 方法,那么这两个方法是怎么被调用的呢?</strong></p>
<h2 id="ObjectOutputStream">ObjectOutputStream</h2>
<p>从code 4中,我们可以看出,对象的序列化过程通过ObjectOutputStream和ObjectInputputStream来实现的,那么带着刚刚的问题,我们来分析一下ArrayList中的writeObject 和 readObject 方法到底是如何被调用的呢?</p>
<p>为了节省篇幅,这里给出ObjectOutputStream的writeObject的调用栈:</p>
<p><code>writeObject ---> writeObject0 --->writeOrdinaryObject--->writeSerialData--->invokeWriteObject</code></p>
<p>这里看一下invokeWriteObject:</p>
<pre class="brush:php;toolbar:false">void invokeWriteObject(Object obj, ObjectOutputStream out)
        throws IOException, UnsupportedOperationException
    {        if (writeObjectMethod != null) {            try {
                writeObjectMethod.invoke(obj, new Object[]{ out });
            } catch (InvocationTargetException ex) {                Throwable th = ex.getTargetException();                if (th instanceof IOException) {                    throw (IOException) th;
                } else {
                    throwMiscException(th);
                }
            } catch (IllegalAccessException ex) {                // should not occur, as access checks have been suppressed
                throw new InternalError(ex);
            }
        } else {            throw new UnsupportedOperationException();
        }
    }

其中writeObjectMethod.invoke(obj, new Object[]{ out });是关键,通过反射的方式调用writeObjectMethod方法。官方是这么解释这个writeObjectMethod的:

class-defined writeObject method, or null if none

在我们的例子中,这个方法就是我们在ArrayList中定义的writeObject方法。通过反射的方式被调用了。

至此,我们先试着来回答刚刚提出的问题:

如果一个类中包含writeObject 和 readObject 方法,那么这两个方法是怎么被调用的?

答:在使用ObjectOutputStream的writeObject方法和ObjectInputStream的readObject方法时,会通过反射的方式调用。

至此,我们已经介绍完了ArrayList的序列化方式。那么,不知道有没有人提出这样的疑问:

Serializable明明就是一个空的接口,它是怎么保证只有实现了该接口的方法才能进行序列化与反序列化的呢?

Serializable接口的定义:

public interface Serializable {
}

读者可以尝试把code 1中的继承Serializable的代码去掉,再执行code 2,会抛出java.io.NotSerializableException

其实这个问题也很好回答,我们再回到刚刚ObjectOutputStream的writeObject的调用栈:

writeObject ---> writeObject0 --->writeOrdinaryObject--->writeSerialData--->invokeWriteObject

writeObject0方法中有这么一段代码:

if (obj instanceof String) {                writeString((String) obj, unshared);
            } else if (cl.isArray()) {                writeArray(obj, desc, unshared);
            } else if (obj instanceof Enum) {                writeEnum((Enum>) obj, desc, unshared);
            } else if (obj instanceof Serializable) {                writeOrdinaryObject(obj, desc, unshared);
            } else {
                if (extendedDebugInfo) {
                    throw new NotSerializableException(
                        cl.getName() + "\n" + debugInfoStack.toString());
                } else {
                    throw new NotSerializableException(cl.getName());
                }
            }

在进行序列化操作时,会判断要被序列化的类是否是Enum、Array和Serializable类型,如果不是则直接抛出NotSerializableException

总结

1、如果一个类想被序列化,需要实现Serializable接口。否则将抛出NotSerializableException异常,这是因为,在序列化操作过程中会对类型进行检查,要求被序列化的类必须属于Enum、Array和Serializable类型其中的任何一种。

2、在变量声明前加上该关键字,可以阻止该变量被序列化到文件中。

3、在类中增加writeObject 和 readObject 方法可以实现自定义序列化策略

推荐学习:《java视频教程

위 내용은 Java 직렬화 및 역직렬화에 대한 심층 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명
이 기사는 掘金에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제
Java의 플랫폼 독립성을 위협하거나 향상시키는 새로운 기술이 있습니까?Java의 플랫폼 독립성을 위협하거나 향상시키는 새로운 기술이 있습니까?Apr 24, 2025 am 12:11 AM

신흥 기술은 위협을 일으키고 Java의 플랫폼 독립성을 향상시킵니다. 1) Docker와 같은 클라우드 컴퓨팅 및 컨테이너화 기술은 Java의 플랫폼 독립성을 향상 시키지만 다양한 클라우드 환경에 적응하도록 최적화되어야합니다. 2) WebAssembly는 Graalvm을 통해 Java 코드를 컴파일하여 플랫폼 독립성을 확장하지만 성능을 위해 다른 언어와 경쟁해야합니다.

JVM의 다른 구현은 무엇이며, 모두 같은 수준의 플랫폼 독립성을 제공합니까?JVM의 다른 구현은 무엇이며, 모두 같은 수준의 플랫폼 독립성을 제공합니까?Apr 24, 2025 am 12:10 AM

다른 JVM 구현은 플랫폼 독립성을 제공 할 수 있지만 성능은 약간 다릅니다. 1. OracleHotspot 및 OpenJDKJVM 플랫폼 독립성에서 유사하게 수행되지만 OpenJDK에는 추가 구성이 필요할 수 있습니다. 2. IBMJ9JVM은 특정 운영 체제에서 최적화를 수행합니다. 3. Graalvm은 여러 언어를 지원하며 추가 구성이 필요합니다. 4. AzulzingJVM에는 특정 플랫폼 조정이 필요합니다.

플랫폼 독립성은 개발 비용과 시간을 어떻게 줄입니까?플랫폼 독립성은 개발 비용과 시간을 어떻게 줄입니까?Apr 24, 2025 am 12:08 AM

플랫폼 독립성은 여러 운영 체제에서 동일한 코드 세트를 실행하여 개발 비용을 줄이고 개발 시간을 단축시킵니다. 구체적으로, 그것은 다음과 같이 나타납니다. 1. 개발 시간을 줄이면 하나의 코드 세트 만 필요합니다. 2. 유지 보수 비용을 줄이고 테스트 프로세스를 통합합니다. 3. 배포 프로세스를 단순화하기위한 빠른 반복 및 팀 협업.

Java의 플랫폼 독립성은 코드 재사용을 어떻게 촉진합니까?Java의 플랫폼 독립성은 코드 재사용을 어떻게 촉진합니까?Apr 24, 2025 am 12:05 AM

Java'SplatformIndenceFacilitatesCodereScoderEByWatHeAveringByTeCodetOrunonAnyPlatformwitHajvm.1) DevelopersCanwriteCodeOnceforConsentEStentBehaviorAcRossPlatforms.2) MAINTENDUCEDSCODEDOES.3) LIBRRIESASHSCORAREDERSCRAPERAREDERSPROJ

Java 응용 프로그램에서 플랫폼 별 문제를 어떻게 해결합니까?Java 응용 프로그램에서 플랫폼 별 문제를 어떻게 해결합니까?Apr 24, 2025 am 12:04 AM

Java 응용 프로그램의 플랫폼 별 문제를 해결하려면 다음 단계를 수행 할 수 있습니다. 1. Java의 시스템 클래스를 사용하여 시스템 속성을보고 실행중인 환경을 이해합니다. 2. 파일 클래스 또는 java.nio.file 패키지를 사용하여 파일 경로를 처리하십시오. 3. 운영 체제 조건에 따라 로컬 라이브러리를로드하십시오. 4. visualVM 또는 JProfiler를 사용하여 크로스 플랫폼 성능을 최적화하십시오. 5. 테스트 환경이 Docker Containerization을 통해 생산 환경과 일치하는지 확인하십시오. 6. githubactions를 사용하여 여러 플랫폼에서 자동 테스트를 수행하십시오. 이러한 방법은 Java 응용 프로그램에서 플랫폼 별 문제를 효과적으로 해결하는 데 도움이됩니다.

JVM의 클래스 로더 서브 시스템은 플랫폼 독립성에 어떻게 기여합니까?JVM의 클래스 로더 서브 시스템은 플랫폼 독립성에 어떻게 기여합니까?Apr 23, 2025 am 12:14 AM

클래스 로더는 통합 클래스 파일 형식, 동적로드, 부모 위임 모델 및 플랫폼 독립적 인 바이트 코드를 통해 다른 플랫폼에서 Java 프로그램의 일관성과 호환성을 보장하고 플랫폼 독립성을 달성합니다.

Java 컴파일러는 플랫폼 별 코드를 생성합니까? 설명하다.Java 컴파일러는 플랫폼 별 코드를 생성합니까? 설명하다.Apr 23, 2025 am 12:09 AM

Java 컴파일러가 생성 한 코드는 플랫폼 독립적이지만 궁극적으로 실행되는 코드는 플랫폼 별입니다. 1. Java 소스 코드는 플랫폼 독립적 인 바이트 코드로 컴파일됩니다. 2. JVM은 바이트 코드를 특정 플랫폼의 기계 코드로 변환하여 크로스 플랫폼 작동을 보장하지만 성능이 다를 수 있습니다.

JVM은 다른 운영 체제에서 멀티 스레딩을 어떻게 처리합니까?JVM은 다른 운영 체제에서 멀티 스레딩을 어떻게 처리합니까?Apr 23, 2025 am 12:07 AM

멀티 스레딩은 프로그램 대응 성과 리소스 활용을 향상시키고 복잡한 동시 작업을 처리 할 수 ​​있기 때문에 현대 프로그래밍에서 중요합니다. JVM은 스레드 매핑, 스케줄링 메커니즘 및 동기화 잠금 메커니즘을 통해 다양한 운영 체제에서 멀티 스레드의 일관성과 효율성을 보장합니다.

See all articles

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

Video Face Swap

Video Face Swap

완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

뜨거운 도구

에디트플러스 중국어 크랙 버전

에디트플러스 중국어 크랙 버전

작은 크기, 구문 강조, 코드 프롬프트 기능을 지원하지 않음

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

Dreamweaver Mac版

Dreamweaver Mac版

시각적 웹 개발 도구

MinGW - Windows용 미니멀리스트 GNU

MinGW - Windows용 미니멀리스트 GNU

이 프로젝트는 osdn.net/projects/mingw로 마이그레이션되는 중입니다. 계속해서 그곳에서 우리를 팔로우할 수 있습니다. MinGW: GCC(GNU Compiler Collection)의 기본 Windows 포트로, 기본 Windows 애플리케이션을 구축하기 위한 무료 배포 가능 가져오기 라이브러리 및 헤더 파일로 C99 기능을 지원하는 MSVC 런타임에 대한 확장이 포함되어 있습니다. 모든 MinGW 소프트웨어는 64비트 Windows 플랫폼에서 실행될 수 있습니다.