国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

從java的NIO版hello world看java源碼,我們能看到什么?

isaced / 2016人閱讀

摘要:這里以為例,它實(shí)際上就是個(gè)使用的一系列方法,比如等,操作文件描述符是什么本身只是獲取通信的服務(wù)和端口的一個(gè)實(shí)現(xiàn)類,對(duì)于服務(wù)的連接,是通過自身的屬性來處理。

Java NIO服務(wù)端代碼的hello world怎么寫?
public class NBTimeServer {

    public static void main(String[] args) {

        try {
            Selector acceptSelector = SelectorProvider.provider().openSelector();
            //創(chuàng)建一個(gè)新的server socket,設(shè)置為非阻塞模式
            ServerSocketChannel ssc = ServerSocketChannel.open();
            ssc.configureBlocking(false);

            // 綁定server sokcet到本機(jī)和對(duì)應(yīng)的端口

            InetAddress lh = InetAddress.getLocalHost();
            InetSocketAddress isa = new InetSocketAddress(lh, 8900);
            ssc.socket().bind(isa);

            //通過selector注冊(cè)server socket,這里即告訴selector,當(dāng)accept發(fā)生的時(shí)候,socket會(huì)被放在reday隊(duì)列
            SelectionKey acceptKey = ssc.register(acceptSelector,
                    SelectionKey.OP_ACCEPT);

            int keysAdded = 0;

            // 當(dāng)任何一個(gè)注冊(cè)事件發(fā)生的時(shí)候,select就會(huì)返回
            while ((keysAdded = acceptSelector.select()) > 0) {
                // 獲取已經(jīng)準(zhǔn)備好的selectorkey
                Set readyKeys = acceptSelector.selectedKeys();
                Iterator i = readyKeys.iterator();


                while (i.hasNext()) {
                    SelectionKey sk = (SelectionKey)i.next();
                    i.remove();
                    ServerSocketChannel nextReady =
                            (ServerSocketChannel)sk.channel();
                    Socket s = nextReady.accept().socket();
                    PrintWriter out = new PrintWriter(s.getOutputStream(), true);
                    Date now = new Date();
                    out.println(now);
                    out.close();
                }
            }
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}
1: 獲取selector。

SelectorProvider提供的所有provider都是同一個(gè)對(duì)象。如果沒有,它會(huì)通過AccessController.doPrivileged來給獲取provider的代碼最高的權(quán)限,執(zhí)行邏輯是:

java.nio.channels.spi.SelectorProvider 是否有配置,有就通過反射創(chuàng)建(本例沒有)

是不是在jar中已經(jīng)實(shí)例化了 java.nio.channels.spi.SelectorProvider,并且他能夠通過getSystemClassLoader加載,就是用第一個(gè)獲取到的SelectorProvider(本例沒有)

最終通過sun.nio.ch.DefaultSelectorProvider類來創(chuàng)建,它在不同的操作系統(tǒng)下有著不同的實(shí)現(xiàn)


以solaris的實(shí)現(xiàn)為例,創(chuàng)建的provider會(huì)根據(jù)操作系統(tǒng)的版本和操作系統(tǒng)的名字分別創(chuàng)建不同的實(shí)例

if ("SunOS".equals(osname)) {
        return new sun.nio.ch.DevPollSelectorProvider();
}
if("Linux".equals(osname)){
     if (major > 2 || (major == 2 && minor >= 6)) {
        return new sun.nio.ch.EPollSelectorProvider();
    }
}
 return new sun.nio.ch.PollSelectorProvider(); //默認(rèn)返回
代碼存在縮減,只取核心

類之間的關(guān)系如下

下面只關(guān)注Epoll和Poll

拿到provider之后,開始執(zhí)行openSelector,獲取真正的selector。
對(duì)于poll,返回的實(shí)例是PollSelectorImpl,對(duì)于Epoll返回的實(shí)例則是EpollSelectorImpl。

file descriptor :unix設(shè)計(jì)哲學(xué)就是一切都是文件,它可能是一個(gè)網(wǎng)絡(luò)連接、一個(gè)終端等等。它本身就是一個(gè)數(shù)值,在系統(tǒng)中會(huì)維護(hù)文件描述符和它對(duì)應(yīng)文件的一個(gè)指針,從而找到對(duì)應(yīng)的文件操作

fd0的獲取主要是調(diào)用Native方法實(shí)現(xiàn)

long pipeFds = IOUtil.makePipe(false);
fd0 = (int) (pipeFds >>> 32); // >>> 表示無符號(hào)右移,最高位補(bǔ)0,這里即獲取讀文件描述符
fd1 = (int) pipeFds; //截掉了高位,存儲(chǔ)的是讀文件描述符

IOUtil針對(duì)不同的操作系統(tǒng)有不同的實(shí)現(xiàn),以solaris為例,它的實(shí)現(xiàn)在IOUtil.c中,主要實(shí)現(xiàn)即通過Linux pipe方法和Linux fcntl方法 (代碼有刪減)

 int fd[2];
  if (pipe(fd) < 0) // 獲取讀和寫的文件符
  if ((configureBlocking(fd[0], JNI_FALSE) < 0) //標(biāo)注為非阻塞
       || (configureBlocking(fd[1], JNI_FALSE) < 0))
  return ((jlong) fd[0] << 32) | (jlong) fd[1]; //讀的文件描述符放在高位,寫的文件描述符放在低位

configureBlocking本身的實(shí)現(xiàn)在IOUtil.c中

static int configureBlocking(int fd, jboolean blocking) //設(shè)置為非阻塞狀態(tài)
{
   int flags = fcntl(fd, F_GETFL); 
   int newflags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
   return (flags == newflags) ? 0 : fcntl(fd, F_SETFL, newflags);
}

pipe實(shí)際是創(chuàng)建了一個(gè)進(jìn)程間通信的單向數(shù)據(jù)管道,參數(shù)中的fd[0]表示管道讀取端的結(jié)尾,fd[1]表示管道寫端的結(jié)尾;fcntl則主要是根據(jù)第二個(gè)參數(shù),如源碼中的F_GETFL和F_SETFL,對(duì)第一個(gè)參數(shù)執(zhí)行對(duì)應(yīng)的操作;

新建EPollArrayWrapper,部分字段如下

pollWrapper = new EPollArrayWrapper();
pollWrapper.initInterrupt(fd0, fd1);

epfd:通過Native方法去構(gòu)建,對(duì)應(yīng)的實(shí)現(xiàn)在EPollArrayWrapper.c中,方法為:Java_sun_nio_ch_EPollArrayWrapper_epollCreate,主要的實(shí)現(xiàn)邏輯是int epfd = (*epoll_create_func)(256);而epoll_create_func在Java_sun_nio_ch_EPollArrayWrapper_init執(zhí)行的時(shí)候已經(jīng)是執(zhí)行了初始化,對(duì)應(yīng)的是Linux epoll_create ,返回既是一個(gè)epoll實(shí)例,它實(shí)質(zhì)也是一個(gè)文件描述符

   epoll_create_func = (epoll_create_t) dlsym(RTLD_DEFAULT, "epoll_create");
   epoll_ctl_func    = (epoll_ctl_t)    dlsym(RTLD_DEFAULT, "epoll_ctl");
   epoll_wait_func   = (epoll_wait_t)   dlsym(RTLD_DEFAULT, "epoll_wait");

pollArray:一個(gè)用來存儲(chǔ)從epoll_wait中得到結(jié)果的數(shù)組,它的大小為 NUM_EPOLLEVENTS * SIZE_EPOLLEVENT,其中的NUM_EPOLLEVENTS則是去的文件描述符限制和8192相比的最小值Math.min(fdLimit(), 8192);詳見Linux getrlimit,實(shí)質(zhì)是AllocatedNativeObject

initInterrupt:出了存儲(chǔ)對(duì)應(yīng)的文件描述符之外,還執(zhí)行了epollCtl(epfd, EPOLL_CTL_ADD, fd0, EPOLLIN);,即把fd0注冊(cè)到epfd上,將epfd上的EPOLLIN事件關(guān)聯(lián)到fd0上,詳見Linux epoll_ctl

新建PollArrayWrapper,部分字段如下

pollWrapper = new PollArrayWrapper(INIT_CAP); //初始為10
pollWrapper.initInterrupt(fd0, fd1);
pollArray:它的大小為(10+1)*SIZE_POLLFD(SIZE_POLLFD取值為8),實(shí)質(zhì)是AllocatedNativeObject

AllocatedNativeObject

NativeObject是用來操作本地內(nèi)存的一個(gè)代理,所有的操作通過Unsafe來實(shí)現(xiàn),它本身是一個(gè)單例
2: 開啟服務(wù)端socket的channel

它還是會(huì)去獲取系統(tǒng)級(jí)別的provider,由于已經(jīng)在拿selector的時(shí)候初始化,不再新建。同樣會(huì)通過PollSelectorProvider或者是EPollSelectorProvider來開啟服務(wù)端的socket的channel,而二者的實(shí)現(xiàn)均是通過父類SelectorProviderImpl,創(chuàng)建一個(gè)ServerSocketChannelImpl實(shí)例

channel:代表與硬件、文件、網(wǎng)絡(luò)socket或者是程序組件等能夠進(jìn)行一些I/O操作(讀和寫)的實(shí)體的連接

Closeable:是關(guān)閉與流相關(guān)的系統(tǒng)資源

AutoCloseable:從1.7開始的支持的語法糖try-with-resources結(jié)構(gòu),實(shí)現(xiàn)自動(dòng)關(guān)閉資源

SelectableChannel:支持通過selector復(fù)用的Channel,提供對(duì)channel的注冊(cè),返回對(duì)應(yīng)的SelectionKey,可以工作在阻塞(默認(rèn))和非阻塞模式下

NetworkChannel:對(duì)應(yīng)網(wǎng)絡(luò)socket的channel,提供將socket綁定到本機(jī)地址的bind方法

fd是使用IOUtil.newFD創(chuàng)建,創(chuàng)建過程如下:

調(diào)用 Native方法 Net.socket0

Net.scoket0 方法對(duì)應(yīng)的實(shí)現(xiàn)為Net.c中的Java_sun_nio_ch_Net_socket0,從頭文件的引入 #include  可以看到,socket0的內(nèi)部很多實(shí)現(xiàn)都依賴于操作系統(tǒng)本身,操作系統(tǒng)不一樣,就會(huì)有不同的調(diào)用結(jié)果。關(guān)鍵實(shí)現(xiàn)如下

fd = socket(domain, type, 0);
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg,sizeof(arg))

socket(family, type, protocol):其中family指的是要在解釋名稱時(shí)使用的地址格式(AF_INET6/AF_INET等),type指定的是通信的語義(SOCK_STREAM/SOCK_DGRAM等),protocol執(zhí)行通信用的協(xié)議,0意味著使用默認(rèn)的。它返回的就是socket file descriptor。詳見Linux socketAPI [solaris 下存在兩套實(shí)現(xiàn),BSD風(fēng)格socket庫-3SOCKET和 GNU/Linux軟件使用這個(gè)庫 XNET ]

setsockop:給文件描述符fd設(shè)置socket的選項(xiàng),返回值小于0表示出了異常,詳見Linux setsocketopt

新建java對(duì)象FileDescriptor ,將1中返回值和新建對(duì)象一起交給IOUtil的Native方法setfdVal執(zhí)行

在IOUtil.c中存在方法 Java_sun_nio_ch_IOUtil_setfdVal,它就是調(diào)用JNI的方法將獲取的值存入到j(luò)ava對(duì)象FileDescriptor中取
FileDescriptor的實(shí)例是用來表示1個(gè)打開的文件,或者是一個(gè)打開的socket或者類似的字節(jié)源

fdVal的賦值則是使用創(chuàng)建好的fd調(diào)用JNI中的(*env)->GetIntField(env, fdo, fd_fdID);實(shí)現(xiàn)

3:獲取socket

本質(zhì)是通過ServerSocketAdaptor創(chuàng)建一個(gè)實(shí)例返回


ServerSocket本質(zhì)是一個(gè)對(duì)SocketImpl的包裝類,相關(guān)的請(qǐng)求處理都是由impl來處理

SocksSocketImpl是按照SOCKS協(xié)議的TCP socket實(shí)現(xiàn),而PlainSocketImpl則是一個(gè)‘平凡’的socket實(shí)現(xiàn),它不對(duì)防火墻或者代理做任何的突破。
SocketImpl是所有實(shí)現(xiàn)socket的父抽象類,用來創(chuàng)建客戶端和服務(wù)端的socket

Socket類是兩臺(tái)機(jī)器之間通信的端點(diǎn),端點(diǎn)(endpoint)指的是 服務(wù)IP和它的端口,它的實(shí)際操作還是由SocketImpl來實(shí)現(xiàn)。

SOCKS4(SOCKets縮寫)是一個(gè)網(wǎng)絡(luò)協(xié)議,它主要負(fù)責(zé)在防火墻上中繼TCP會(huì)話,以便應(yīng)用用戶能夠透過防火墻進(jìn)行訪問。它主要定義了兩個(gè)操作:CONNECT和BIND。

需要CONNECT時(shí),客戶端發(fā)送一個(gè)CONNECT請(qǐng)求給SOCKS服務(wù)器,請(qǐng)求包含要連接的目的端口和目的主機(jī)等信息,SOCKS服務(wù)器會(huì)做一些服務(wù)權(quán)限的校驗(yàn),驗(yàn)證成功SOCKS服務(wù)器建立與目標(biāo)主機(jī)指定端口的連接(即應(yīng)用服務(wù)器),然后發(fā)送反饋包給客戶端,反饋包通過CD的值來標(biāo)識(shí)CONNECT請(qǐng)求的結(jié)果,CONNECT成功,SOCKS就可以在兩個(gè)方向上轉(zhuǎn)發(fā)流量了

BIND必須發(fā)生在CONNECT之后,它實(shí)際包括一系列的步驟:1 獲取socket;2 拿到scoket對(duì)應(yīng)的端口和ip地址;3 開始監(jiān)聽,準(zhǔn)備接收來自應(yīng)用服務(wù)器的調(diào)用 4:使用主連接通知應(yīng)用服務(wù)器它需要連接的IP地址和端口 5:接收一個(gè)來自應(yīng)用服務(wù)器的連接

SOCKS5相對(duì)于SOCKS4做了功能擴(kuò)展,支持UDP、IPV6、鑒定的支持

4:綁定服務(wù)器和它的端口

ServerSocketChannelImpl的bind方法。
1: 看看當(dāng)前channel是不是已經(jīng)綁定或者關(guān)閉,如果完成,拋出相關(guān)異常
2: 看看是否有分配服務(wù)器,沒有就隨便建一個(gè)

public InetSocketAddress(int port) {    
    this(InetAddress.anyLocalAddress(), port);
}

3: 獲取系統(tǒng)的SecurityManager,獲取成功,就去檢查線程是否有權(quán)限來操作端口等待連接到來,不行則拋出SecurityException
4: NetHooks.beforeTcpBind ,如果使用了com.sun.sdp.conf配置,那么將會(huì)把Tcp Socket包裝成Sdp Socket(Hello world沒有啟用)
5: 執(zhí)行綁定,實(shí)際執(zhí)行Native方法Net.bind0,對(duì)應(yīng)Net.c中的Java_sun_nio_ch_Net_bind0方法,關(guān)鍵代碼如下

//將傳入的java對(duì)象的InetAddress和端口轉(zhuǎn)換為結(jié)構(gòu)體:sockaddr_in或者sockaddr_in6
NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, preferIPv6);
rv = NET_Bind(fdval(env, fdo), (struct sockaddr *)&sa, sa_len);
bind對(duì)于windows系統(tǒng)和linux系統(tǒng)有不同的實(shí)現(xiàn),以Linux為例,它實(shí)際執(zhí)行的就是Linux bind,所做的操作就是把指定的地址(SocketAddress)分配給socket文件描述符,對(duì)于Hello world的實(shí)現(xiàn)來說就是它的字段fd

6: 監(jiān)聽,實(shí)際為Linux listen,表明這個(gè)socket將會(huì)用來接收即將到來的連接請(qǐng)求

5:通過selector注冊(cè)channel


注冊(cè)事件在實(shí)質(zhì)上就是維護(hù)新建channel的文件描述符和SelectionKey的關(guān)系,就實(shí)現(xiàn)上而言, Poll用的是數(shù)組,Epoll用的是HashMap

合法的操作為SelectionKey.OP_READ、SelectionKey.OP_WRITE、SelectionKey.OP_CONNECT
6:從selector獲取任何已經(jīng)注冊(cè)好并發(fā)生的事件


根據(jù)是Poll還是Epoll有不同的實(shí)現(xiàn)。select的實(shí)質(zhì)就是去獲取poll和epoll的結(jié)果,然后更新自身維護(hù)的selector結(jié)構(gòu)對(duì)應(yīng)的狀態(tài)

7:接收已經(jīng)準(zhǔn)備好的channel傳過來的數(shù)據(jù)

在非阻塞模式下,accept會(huì)立馬返回

Linux accept 實(shí)際上就是從監(jiān)聽狀態(tài)的socketfd的連接等待隊(duì)列中獲取第一個(gè)連接請(qǐng)求,然后新建一個(gè)socket返回。

這里新建的SocketChannelImpl,而之前使用的是ServerSocketChannelImpl。區(qū)別在于 SocketChannelImpl支持讀寫數(shù)據(jù),而ServerSocketChannelImpl則更多的用于等待連接的到來,充當(dāng)服務(wù)端

接下來,獲取的socket方式同第3步中新建socket

8:從socket中獲取outputStream

outpusStream通過Channels.newOutputStream新建,它會(huì)持有accept處新建的SocketChannelImpl,它實(shí)際上就是新建OutputStream并重寫它的write方法

9:回寫數(shù)據(jù)

printWriter的print經(jīng)過BufferWriter到OutputStreamWriter,再到它的StreamEncoder到它的方法writeBytes執(zhí)行 out.write(bb.array(), bb.arrayOffset() + pos, rem);即socket中重寫的write方法,它的主要實(shí)現(xiàn)是調(diào)用Channels.writeFully,然后調(diào)用Channel自己的SocketChannelImpl.write方法,它核心在于 n = IOUtil.write(fd, buf, -1, nd, writeLock);

 static int write(FileDescriptor fd, ByteBuffer src, long position,
                     NativeDispatcher nd, Object lock)
        throws IOException
    {
        //判斷是否是直接內(nèi)存
        if (src instanceof DirectBuffer)
            return writeFromNativeBuffer(fd, src, position, nd, lock);

        // Substitute a native buffer
        int pos = src.position();
        int lim = src.limit();
        assert (pos <= lim);
        int rem = (pos <= lim ? lim - pos : 0);
        //申請(qǐng)一個(gè)DirectBuffer,即通過ByteBuffer.allocateDirect來申請(qǐng)直接內(nèi)存;
        ByteBuffer bb = Util.getTemporaryDirectBuffer(rem);
        try {
            bb.put(src);
            bb.flip();
            // Do not update src until we see how many bytes were written
            src.position(pos);
            //寫數(shù)據(jù),實(shí)際上執(zhí)行的是FileDispatcherImpl的Native方法writ0
            int n = writeFromNativeBuffer(fd, bb, position, nd, lock);
            if (n > 0) {
                // now update src
                src.position(pos + n);
            }
            return n;
        } finally {
            Util.offerFirstTemporaryDirectBuffer(bb);
        }
    }

可以看到這里有一段從JVM的Buffer拷貝到NativeBuffer中,也就是說NIO的數(shù)據(jù)寫肯定是從直接內(nèi)存發(fā)送出去的,如果本身不是直接內(nèi)存則會(huì)經(jīng)過一次內(nèi)存拷貝。

JNIEXPORT jint JNICALL
Java_sun_nio_ch_FileDispatcherImpl_write0(JNIEnv *env, jclass clazz,
                              jobject fdo, jlong address, jint len)
{
    jint fd = fdval(env, fdo);
    void *buf = (void *)jlong_to_ptr(address);

    return convertReturnVal(env, write(fd, buf, len), JNI_FALSE);
}

最終的寫可以看到用的就是Linux write

Java NIO的本質(zhì)是什么? 為什么一個(gè)Selector管理了多個(gè)Channel?

SelectionKey會(huì)持有各自操作系統(tǒng)下的SelectorImpl對(duì)象,對(duì)于PollSelectorImpl的channel注冊(cè)內(nèi)部實(shí)際是通過數(shù)組存儲(chǔ)了文件描述符和Selector的關(guān)系,EpollSelectorImpl的channel注冊(cè)則是內(nèi)部用的HashMap存儲(chǔ)文件描述符和Selector的關(guān)系。當(dāng)讀取到事件的時(shí)候,就通過輪詢的方式拿到所有準(zhǔn)備好的事件返回,一個(gè)個(gè)的處理

NIO是如何實(shí)現(xiàn)的?

它依賴于操作系統(tǒng)本身,對(duì)于windows/mac/linux均有不同的版本實(shí)現(xiàn)。這里以Liunx為例,它實(shí)際上就是個(gè)使用Linux的一系列方法,比如 read/write/accept等,操作文件描述符

socket是什么?

socket本身只是獲取通信的服務(wù)和端口的一個(gè)實(shí)現(xiàn)類,對(duì)于服務(wù)的連接,是通過自身的屬性來處理。而這個(gè)屬性impl實(shí)際也就是對(duì)SOCKS協(xié)議的實(shí)現(xiàn)。來提供連接和綁定服務(wù)。

Java 阻塞IO服務(wù)端代碼的hello world怎么寫?
public class TimeServer {

    private static Charset charset = Charset.forName("US-ASCII");
    private static CharsetEncoder encoder = charset.newEncoder();

    public static void main(String[] args) throws IOException {
        ServerSocketChannel ssc = ServerSocketChannel.open();
        InetSocketAddress isa = new InetSocketAddress(InetAddress.getLocalHost(), 8013);
        ssc.socket().bind(isa);
        for (;;)
        {
            SocketChannel sc = ssc.accept();
            try {
                String now = new Date().toString();
                sc.write(encoder.encode(CharBuffer.wrap(now + "
")));
                System.out.println(sc.socket().getInetAddress() + " : " + now);
                sc.close();
            } finally {
                // Make sure we close the channel (and hence the socket)
                sc.close();
            }
        }
    }

}

它與NIO的區(qū)別主要區(qū)別在于在于,NIO通過configureBlocking設(shè)置為false,會(huì)把它自身的fd設(shè)置為非阻塞,而阻塞IO則沒有,默認(rèn)阻塞。

Java客戶端的hello world怎么寫?
public class TimeQuery {

    // Charset and decoder for US-ASCII
    private static Charset charset = Charset.forName("US-ASCII");
    private static CharsetDecoder decoder = charset.newDecoder();

    // Direct byte buffer for reading
    private static ByteBuffer dbuf = ByteBuffer.allocateDirect(1024);

    public static void main(String[] args) {
            try {
                InetSocketAddress isa = new InetSocketAddress(InetAddress.getLocalHost(), 8900);
                SocketChannel sc = null;
                try {

                    // Connect
                    sc = SocketChannel.open();
                    sc.connect(isa);

                    // Read the time from the remote host.  For simplicity we assume
                    // that the time comes back to us in a single packet, so that we
                    // only need to read once.
                    dbuf.clear();
                    sc.read(dbuf);

                    // Print the remote address and the received time
                    dbuf.flip();
                    CharBuffer cb = decoder.decode(dbuf);
                    System.out.print(isa + " : " + cb);

                } finally {
                    // Make sure we close the channel (and hence the socket)
                    if (sc != null)
                        sc.close();
                }
            } catch (IOException x) {
                System.err.println( x);
            }
    }

}

真實(shí)的執(zhí)行實(shí)際上也就是Linux connect和Linux read

附錄

jdk 7 源碼地址
NIO服務(wù)端 源碼地址
IO服務(wù)端 源碼地址
客戶端 源碼地址
如何讀open jdk native 源碼
java JNI簡介

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/71591.html

相關(guān)文章

  • Java開發(fā)

    摘要:大多數(shù)待遇豐厚的開發(fā)職位都要求開發(fā)者精通多線程技術(shù)并且有豐富的程序開發(fā)調(diào)試優(yōu)化經(jīng)驗(yàn),所以線程相關(guān)的問題在面試中經(jīng)常會(huì)被提到。將對(duì)象編碼為字節(jié)流稱之為序列化,反之將字節(jié)流重建成對(duì)象稱之為反序列化。 JVM 內(nèi)存溢出實(shí)例 - 實(shí)戰(zhàn) JVM(二) 介紹 JVM 內(nèi)存溢出產(chǎn)生情況分析 Java - 注解詳解 詳細(xì)介紹 Java 注解的使用,有利于學(xué)習(xí)編譯時(shí)注解 Java 程序員快速上手 Kot...

    LuDongWei 評(píng)論0 收藏0
  • java 基礎(chǔ) - 收藏集 - 掘金

    摘要:基礎(chǔ)知識(shí)復(fù)習(xí)后端掘金的作用表示靜態(tài)修飾符,使用修飾的變量,在中分配內(nèi)存后一直存在,直到程序退出才釋放空間。將對(duì)象編碼為字節(jié)流稱之為序列化,反之將字節(jié)流重建成對(duì)象稱之為反序列化。 Java 學(xué)習(xí)過程|完整思維導(dǎo)圖 - 后端 - 掘金JVM 1. 內(nèi)存模型( 內(nèi)存分為幾部分? 堆溢出、棧溢出原因及實(shí)例?線上如何排查?) 2. 類加載機(jī)制 3. 垃圾回收 Java基礎(chǔ) 什么是接口?什么是抽象...

    makeFoxPlay 評(píng)論0 收藏0
  • Java深入-框架技巧

    摘要:從使用到原理學(xué)習(xí)線程池關(guān)于線程池的使用,及原理分析分析角度新穎面向切面編程的基本用法基于注解的實(shí)現(xiàn)在軟件開發(fā)中,分散于應(yīng)用中多出的功能被稱為橫切關(guān)注點(diǎn)如事務(wù)安全緩存等。 Java 程序媛手把手教你設(shè)計(jì)模式中的撩妹神技 -- 上篇 遇一人白首,擇一城終老,是多么美好的人生境界,她和他歷經(jīng)風(fēng)雨慢慢變老,回首走過的點(diǎn)點(diǎn)滴滴,依然清楚的記得當(dāng)初愛情萌芽的模樣…… Java 進(jìn)階面試問題列表 -...

    chengtao1633 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<