亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

深入探究Java多線程并發(fā)編程的要點(diǎn)

 更新時(shí)間:2015年11月03日 08:56:56   作者:守仁  
這篇文章主要介紹了深入探究Java多線程并發(fā)編程的要點(diǎn),包括關(guān)鍵字synchronized的使用和wait()與notify()獲取對象鎖的三種方式,需要的朋友可以參考下

關(guān)鍵字synchronized
synchronized關(guān)鍵可以修飾函數(shù)、函數(shù)內(nèi)語句。無論它加上方法還是對象上,它取得的鎖都是對象,而不是把一段代碼或是函數(shù)當(dāng)作鎖。
1,當(dāng)兩個(gè)并發(fā)線程訪問同一個(gè)對象object中的這個(gè)synchronized(this)同步代碼塊時(shí),一段時(shí)間只能有一個(gè)線程得到執(zhí)行,而另一個(gè)線程只有等當(dāng)前線程執(zhí)行完以后才能執(zhí)行這塊代碼。
2,當(dāng)一個(gè)線程訪問object中的一個(gè)synchronized(this)同步代碼塊時(shí),其它線程仍可以訪問這個(gè)object中是其它非synchronized (this)代碼塊。
3,這里需要注意的是,當(dāng)一個(gè)線程訪問object的一個(gè)synchronized(this)代碼塊時(shí),其它線程對這個(gè)object中其它synchronized (this)同步代碼塊的訪問將被阻塞。
4,以上所述也適用于其它的同步代碼塊,也就是說,當(dāng)一個(gè)線程訪問object的一個(gè)synchronized(this)同步代碼塊時(shí),這個(gè)線程就獲得了object的對象鎖。而且每個(gè)對象(即類實(shí)例)對應(yīng)著一把鎖,每個(gè)synchronized(this)都必須獲得調(diào)用該代碼塊兒(可以函數(shù),也可以是變量)的對象的鎖才能執(zhí)行,否則所屬線程阻塞,方法一旦執(zhí)行就會(huì)獨(dú)占該鎖,直到從方法返回時(shí),也釋放這個(gè)鎖,重新進(jìn)入可執(zhí)行狀態(tài)。這種機(jī)制確保了同一時(shí)刻對于每一個(gè)對象,其所有聲明為synchronized的成員函數(shù)中至多只有一個(gè)處于可執(zhí)行狀態(tài)(因?yàn)橹炼嘀挥幸粋€(gè)線程可以獲取該對象的鎖),從而避免了類成員變量的訪問沖突。
synchronized方式的缺點(diǎn):
由于synchronized鎖定的是調(diào)用這個(gè)同步方法的對象,也就是說,當(dāng)一個(gè)線程P1在不同的線程中執(zhí)行這個(gè)方法時(shí),它們之間會(huì)形成互斥,從而達(dá)到同步的效果。但這里需要注意的是,這個(gè)對象所性的Class的另一個(gè)對象卻可以任意調(diào)用這個(gè)被加了synchronized關(guān)鍵字的方法。同步方法的實(shí)質(zhì)是將synchronized作用于object reference,對于拿到了P1對象鎖的線程才可以調(diào)用這個(gè)synchronized方法,而對于P2來說,P1與它毫不相干,程序也可能在這種情況下擺脫同步機(jī)制的控制,造成數(shù)據(jù)混亂。以下我們將對這種情況進(jìn)行詳細(xì)地說明:
首先我們先介紹synchronized關(guān)鍵字的兩種加鎖對象:對象和類——synchronized可以為資源加對象鎖或是類鎖,類鎖對這個(gè)類的所有對象(實(shí)例)均起作用,而對象鎖只是針對該類的一個(gè)指定的對象加鎖,這個(gè)類的其它對象仍然可以使用已經(jīng)對前一個(gè)對象加鎖的synchronized方法。
在這里我們主要討論的一個(gè)問題就是:“同一個(gè)類,不同實(shí)例調(diào)用同一個(gè)方法,會(huì)產(chǎn)生同步問題嗎?”
同步問題只和資源有關(guān)系,要看這個(gè)資源是不是靜態(tài)的。同一個(gè)靜態(tài)數(shù)據(jù),你相同函數(shù)分屬不同線程同時(shí)對其進(jìn)行讀寫,CPU也不會(huì)產(chǎn)生錯(cuò)誤,它會(huì)保證你代碼的執(zhí)行邏輯,而這個(gè)邏輯是否是你想要的,那就要看你需要什么樣的同步了。即便你兩個(gè)不同的代碼,在CPU的不同的兩個(gè)core里跑,同時(shí)寫一個(gè)內(nèi)存地址,Cache機(jī)制也會(huì)在L2里先鎖定一個(gè)。然后更新,再share給另一個(gè)core,也不會(huì)出錯(cuò),不然intel,amd就白養(yǎng)那么多人了。
因此,只要你沒有兩個(gè)代碼共享的同一個(gè)資源或變量,就不會(huì)出現(xiàn)數(shù)據(jù)不一致的情況。而且同一個(gè)類的不同對象的調(diào)用有完全不同的堆棧,它們之間完全不相干。
以下我們以一個(gè)售票過程舉例說明,在這里,我們的共享資源就是票的剩余張數(shù)。

package com.test;

public class ThreadSafeTest extends Thread implements Runnable {
  
  private static int num = 1;

  public ThreadSafeTest(String name) {
    setName(name);
  }

  public void run() {
    sell(getName());   
  }
  
  private synchronized void sell(String name){
    if (num > 0) {
      System. out.println(name + ": 檢測票數(shù)大于0" );
      System. out.println(name + ": \t正在收款(大約5秒完成)。。。" );
      try {
        Thread. sleep(5000);
        System. out.println(name + ": \t打印票據(jù),售票完成" );
        num--;
        printNumInfo();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    } else {
      System. out.println(name+": 沒有票了,停止售票" );
    }
  }
  
  private static void printNumInfo() {

    System. out.println("系統(tǒng):當(dāng)前票數(shù):" + num);
    if (num < 0) {
      System. out.println("警告:票數(shù)低于0,出現(xiàn)負(fù)數(shù)" );
    }
  }

  public static void main(String args[]) {
    try {
      new ThreadSafeTest("售票員李XX" ).start();
      Thread. sleep(2000);
      new ThreadSafeTest("售票員王X" ).start();
      
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}

運(yùn)行上述代碼,我們得到的輸出是:

售票員李XX: 檢測票數(shù)大于0
售票員李XX:    正在收款(大約5秒完成)。。。
售票員王X: 檢測票數(shù)大于0
售票員王X: 正在收款(大約5秒完成)。。。
售票員李XX:    打印票據(jù),售票完成
系統(tǒng):當(dāng)前票數(shù):0
售票員王X: 打印票據(jù),售票完成
系統(tǒng):當(dāng)前票數(shù):-1
警告:票數(shù)低于0,出現(xiàn)負(fù)數(shù)

根據(jù)輸出結(jié)果,我們可以發(fā)現(xiàn),剩余票數(shù)為-1,出現(xiàn)了同步錯(cuò)誤的問題。之所以出現(xiàn)這種情況的原因是,我們建立的兩個(gè)實(shí)例對象,對共享的靜態(tài)資源static int num = 1同時(shí)進(jìn)行了修改。那么我們將上面代碼中方框內(nèi)的修飾詞static去掉,然后再運(yùn)行程序,可以得到:

售票員李XX: 檢測票數(shù)大于0
售票員李XX:    正在收款(大約5秒完成)。。。
售票員王X: 檢測票數(shù)大于0
售票員王X: 正在收款(大約5秒完成)。。。
售票員李XX:    打印票據(jù),售票完成
系統(tǒng):當(dāng)前票數(shù):0
售票員王X: 打印票據(jù),售票完成
系統(tǒng):當(dāng)前票數(shù):0

對程度修改之后,程序運(yùn)行貌似沒有問題了,每個(gè)對象擁有各自不同的堆棧,分別獨(dú)立運(yùn)行。但這樣卻違背了我們希望多線程同時(shí)對共享資源的處理(去static后,num就從共享資源變成了每個(gè)實(shí)例各自擁有的成員變量),這顯然不是我們想要的。
在以上兩種代碼中,采取的主要是對對象的鎖定。由于我之前談到的原因,當(dāng)一個(gè)類的兩個(gè)不同的實(shí)例對同一共享資源進(jìn)行修改時(shí),CPU為了保證程序的邏輯會(huì)默認(rèn)這種做法,至于是不是想要的結(jié)果,這個(gè)只能由程序員自己來決定。因此,我們需要改變鎖的作用范圍,若作用對象只是實(shí)例,那么這種問題是無法避免的;只有當(dāng)鎖的作用范圍是整個(gè)類的時(shí)候,才可能排除同一個(gè)類的不同實(shí)例對共享資源同時(shí)修改的問題。

package com.test;

public class ThreadSafeTest extends Thread implements Runnable {
  private static int num = 1;

  public ThreadSafeTest(String name) {
    setName(name);
  }

  public void run() {
    sell(getName());   
  }  
  
  private synchronized static void sell(String name){

    if (num > 0) {
      System. out.println(name + ": 檢測票數(shù)大于0" );
      System. out.println(name + ": \t正在收款(大約5秒完成)。。。" );
      try {
        Thread. sleep(5000);
        System. out.println(name + ": \t打印票據(jù),售票完成" );
        num--;
        printNumInfo();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    } else {
      System. out.println(name+": 沒有票了,停止售票" );
    }
  }

  private static void printNumInfo() {
    System. out.println("系統(tǒng):當(dāng)前票數(shù):" + num);
    if (num < 0) {
      System. out.println("警告:票數(shù)低于0,出現(xiàn)負(fù)數(shù)" );
    }
  }

  public static void main(String args[]) {
    try {
      new ThreadSafeTest("售票員李XX" ).start();
      Thread. sleep(2000);
      new ThreadSafeTest("售票員王X" ).start();
      
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}

將程序做如上修改,可以得到運(yùn)行結(jié)果:

售票員李XX: 檢測票數(shù)大于0
售票員李XX:    正在收款(大約5秒完成)。。。
售票員李XX:    打印票據(jù),售票完成
系統(tǒng):當(dāng)前票數(shù):0
售票員王X: 沒有票了,停止售票

對sell()方法加上了static修飾符,這樣就將鎖的作用對象變成了類,當(dāng)該類的一個(gè)實(shí)例對共享變量進(jìn)行操作時(shí)將會(huì)阻塞這個(gè)類的其它實(shí)例對其的操作。從而得到我們?nèi)缙谙胍慕Y(jié)果。
總結(jié):
1,synchronized關(guān)鍵字有兩種用法:synchronized方法和synchronized塊。
2,在Java中不單是類實(shí)例,每一個(gè)類也可以對應(yīng)一把鎖
在使用synchronized關(guān)鍵字時(shí),有以下幾點(diǎn)兒需要注意:
1,synchronized關(guān)鍵字不能被繼承。雖然可以用synchronized來定義方法,但是synchronized卻并不屬于方法定義的一部分,所以synchronized關(guān)鍵字并不能被繼承。如果父類中的某個(gè)方法使用了synchronized關(guān)鍵字,而子類中也覆蓋了這個(gè)方法,默認(rèn)情況下子類中的這個(gè)方法并不是同步的,必須顯示的在子類的這個(gè)方法中加上synchronized關(guān)鍵字才可。當(dāng)然,也可以在子類中調(diào)用父類中相應(yīng)的方法,這樣雖然子類中的方法并不是同步的,但子類調(diào)用了父類中的同步方法,也就相當(dāng)子類方法也同步了。如,
在子類中加synchronized關(guān)鍵字:

class Parent { 
  public synchronized void method() {  } 
} 
class Child extends Parent { 
  public synchronized void method () {  } 
}

調(diào)用父類方法:

class Parent { 
  public synchronized void method() {  } 
} 
class Child extends Parent { 
  public void method() { super.method();  } 
}

2,在接口方法定義時(shí)不能使用synchronized關(guān)鍵字。
3,構(gòu)造方法不能使用synchronized關(guān)鍵字,但可以使用synchronized塊來進(jìn)行同步。
4,synchronized位置可以自由放置,但是不能放置在方法的返回類型后面。
5,synchronized關(guān)鍵字不可以用來同步變量,如下面代碼是錯(cuò)誤的:

public synchronized int n = 0; 
public static synchronized int n = 0;

6,雖然使用synchronized關(guān)鍵字是最安全的同步方法,但若是大量使用也會(huì)造成不必要的資源消耗以及性能損失。從表面上看synchronized鎖定的是一個(gè)方法,但實(shí)際上鎖定的卻是一個(gè)類,比如,對于兩個(gè)非靜態(tài)方法method1()和method2()都使用了synchronized關(guān)鍵字,在執(zhí)行其中的一個(gè)方法時(shí),另一個(gè)方法是不能執(zhí)行的。靜態(tài)方法和非靜態(tài)方法情況類似。但是靜態(tài)方法和非靜態(tài)方法之間不會(huì)相互影響,見如下代碼:

public class MyThread1 extends Thread { 
  public String methodName ; 
 
  public static void method(String s) { 
    System. out .println(s); 
    while (true ); 
  } 
  public synchronized void method1() { 
    method( "非靜態(tài)的method1方法" ); 
  } 
  public synchronized void method2() { 
    method( "非靜態(tài)的method2方法" ); 
  } 
  public static synchronized void method3() { 
    method( "靜態(tài)的method3方法" ); 
  } 
  public static synchronized void method4() { 
    method( "靜態(tài)的method4方法" ); 
  } 
  public void run() { 
    try { 
      getClass().getMethod( methodName ).invoke( this); 
    } 
    catch (Exception e) { 
    } 
  } 
  public static void main(String[] args) throws Exception { 
    MyThread1 myThread1 = new MyThread1(); 
    for (int i = 1; i <= 4; i++) { 
      myThread1. methodName = "method" + String.valueOf (i); 
      new Thread(myThread1).start(); 
      sleep(100); 
    } 
  } 
}

運(yùn)行結(jié)果為:

非靜態(tài)的method1方法
靜態(tài)的method3方法

從上面的運(yùn)行結(jié)果可以看出,method2和method4在method1和method3運(yùn)行完之前是不會(huì)運(yùn)行的。因此,可以得出一個(gè)結(jié)論,如查在類中使用synchronized來定義非靜態(tài)方法,那么將影響這個(gè)類中的所有synchronized定義的非靜態(tài)方法;如果定義的靜態(tài)方法,那么將影響這個(gè)類中所有以synchronized定義的靜態(tài)方法。這有點(diǎn)兒像數(shù)據(jù)表中的表鎖,當(dāng)修改一條記錄時(shí),系統(tǒng)就將整個(gè)表都鎖住了。因此,大量使用這種同步方法會(huì)使程序的性能大幅度地下降。
對共享資源的同步訪問更加安全的技巧:
1,定義private的instance變量+它的get方法,而不要定義public/protected的instance變量。如果將變量定義為public,對象可以在外界繞過同步方法的控制而直接取得它,并且改動(dòng)它。這也是JavaBean的標(biāo)準(zhǔn)實(shí)現(xiàn)之一。
2,如果instance變量是一個(gè)對象,如數(shù)組或ArrayList等,那上述方法仍然不安全,因?yàn)楫?dāng)外界通過get方法拿到這個(gè)instance對象的引用后,又將其指向另一個(gè)對象,那么這個(gè)private變量也就變了,豈不是很危險(xiǎn)。這個(gè)時(shí)候就需要將get方法也加上synchronized同步,并且只返回這個(gè)private對象的clone()。這樣,調(diào)用端得到的就只是對象副本的一個(gè)引用了。

wait()與notify()獲取對象監(jiān)視器(鎖)的三種方式
在某個(gè)線程方法中對wait()和notify()的調(diào)用必須指定一個(gè)Object對象,而且該線程必須擁有該Object對象的monitor。而獲取對象monitor最簡單的辦法就是,在對象上使用synchronized關(guān)鍵字。當(dāng)調(diào)用wait()方法以后,該線程會(huì)釋放掉對象鎖,并進(jìn)入sleep狀態(tài)。而在其它線程調(diào)用notify()方法時(shí),必須使用同一個(gè)Object對象,notify()方法調(diào)用成功后,所在這個(gè)對象上的相應(yīng)的等侍線程將被喚醒。
對于被一個(gè)對象鎖定的多個(gè)方法,在調(diào)用notify()方法時(shí)將會(huì)任選其中一個(gè)進(jìn)行喚醒,而notifyAll()則是將其所有等待線程喚醒。

package net.mindview.util;

import javax.swing.JFrame;

public class WaitAndNotify {
    public static void main(String[] args) {
      System. out.println("Hello World!" );
      WaitAndNotifyJFrame frame = new WaitAndNotifyJFrame();
      frame.setDefaultCloseOperation(JFrame. EXIT_ON_CLOSE);
       // frame.show();
      frame.setVisible( true);
   }
}

@SuppressWarnings("serial" )
class WaitAndNotifyJFrame extends JFrame {

    private WaitAndNotifyThread t ;

    public WaitAndNotifyJFrame() {
      setSize(300, 100);
      setLocation(250, 250);
      JPanel panel = new JPanel();
      JButton start = new JButton(new AbstractAction("Start") {
          public void actionPerformed(ActionEvent event) {
             if (t == null) {
                t = new WaitAndNotifyThread(WaitAndNotifyJFrame.this);
                t.start();
            } else if (t .isWait ) {
                t. isWait = false ;
                t.n();
                // t.notify();
            }
         }
      });
      panel.add(start);
      JButton pause = new JButton(new AbstractAction("Pause") {
          public void actionPerformed(ActionEvent e) {
             if (t != null) {
                t. isWait = true ;
            }
         }
      });
      panel.add(pause);
      JButton end = new JButton(new AbstractAction("End") {
          public void actionPerformed(ActionEvent e) {
             if (t != null) {
                t.interrupt();
                t = null;
            }
         }
      });
      panel.add(end);
      getContentPane().add(panel);
   }

}

@SuppressWarnings("unused" )
class WaitAndNotifyThread extends Thread {

    public boolean isWait ;
    private WaitAndNotifyJFrame control ;
    private int count ;

    public WaitAndNotifyThread(WaitAndNotifyJFrame f) {
       control = f;
       isWait = false ;
       count = 0;
   }

    public void run() {
       try {
          while (true ) {
             synchronized (this ) {
               System. out.println("Count:" + count++);
                sleep(100);
                if (isWait )
                  wait();
            }
         }
      } catch (Exception e) {
      }
   }
    
   public void n() {
       synchronized (this ) {
         notify();
      }
   }

}

如上面例子方框中的代碼,若去掉同步代碼塊,執(zhí)行就會(huì)拋出java.lang.IllegalMonitorStateException異常。
查看JDK,我們可以看到,出現(xiàn)此異常的原因是當(dāng)前線程不是此對象監(jiān)視器的所有者。
此方法只應(yīng)由作為此對象監(jiān)視器的所有者的線程來調(diào)用,通過以下三種方法之一,可以使線程成為此對象監(jiān)視器的所有者:
1,通過執(zhí)行此對象的同步實(shí)例方法,如:
        

  public synchronized void n() {
     notify();
   }

2,通過執(zhí)行在此對象上進(jìn)行同步的synchronized語句的正文,如:
     

 public void n() {
     synchronized (this ) {
       notify();
     }
   }

3,對于Class類型的對象,可以通過執(zhí)行該類的同步靜態(tài)方法。
在調(diào)用靜態(tài)方法時(shí),我們并不一定創(chuàng)建一個(gè)實(shí)例對象。因此,就不能使用this來同步靜態(tài)方法,所以必須使用Class對象來同步靜態(tài)方法,由于notify()方法不是靜態(tài)方法,所以我們無法將n()方法設(shè)置成靜態(tài)方法,所以采用另外一個(gè)例子加以說明:

public class SynchronizedStatic implements Runnable {

    private static boolean flag = true;

//類對象同步方法一:   
   // 注意static修飾的同步方法,監(jiān)視器:SynchronizedStatic.class
    private static synchronized void testSyncMethod() {
       for (int i = 0; i < 100; i++) {
          try {
            Thread. sleep(100);
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
         System. out.println("testSyncMethod:" + i);
      }
   }


//類對象同步方法二:   
      private void testSyncBlock() {
       // 顯示使用獲取class做為監(jiān)視器.它與static synchronized method隱式獲取class監(jiān)視器一樣.
       synchronized (SynchronizedStatic. class) {
          for (int i = 0; i < 100; i++) {
             try {
               Thread. sleep(100);
            } catch (InterruptedException e) {
               e.printStackTrace();
            }
            System. out.println("testSyncBlock:" + i);
         }
      }
   }


    public void run() {
       // flag是static的變量.所以,不同的線程會(huì)執(zhí)行不同的方法,只有這樣才能看到不同的鎖定效果.
       if (flag ) {
          flag = false ;
          testSyncMethod();
      } else {
          flag = true ;
         testSyncBlock();
      }
   }

    public static void main(String[] args) {
      ExecutorService exec = Executors. newFixedThreadPool(2);
      SynchronizedStatic rt = new SynchronizedStatic();
      SynchronizedStatic rt1 = new SynchronizedStatic();
      exec.execute(rt);
      exec.execute(rt1);
      exec.shutdown();
   }
}

以上代碼的運(yùn)行結(jié)果是,讓兩個(gè)同步方法同時(shí)打印從0到99這100個(gè)數(shù),其中方法一是一個(gè)靜態(tài)同步方法,它的作用域?yàn)轭?;方法二顯示的聲明了代碼塊的作用域是類。這兩個(gè)方法的異曲同工的。由于方法一和方法二的作用域同為類,所以它們兩個(gè)方法間是互斥的,也就是說,當(dāng)一個(gè)線程調(diào)用了這兩個(gè)方法中的一個(gè),剩余沒有調(diào)用的方法也會(huì)對其它線程形成阻塞。因此,程序的運(yùn)行結(jié)果會(huì)是:

testSyncMethod:0
testSyncMethod:1
... ...
testSyncMethod:99
testSyncBlock:0
... ...
testSyncBlock:99

但是,如果我們將方法二中的SynchronizedStatic. class替換成this的話,由于作用域的沒,這兩個(gè)方法就不會(huì)形成互斥,程序的輸出結(jié)果也會(huì)交替進(jìn)行,如下所示:

testSyncBlock:0
testSyncMethod:0
testSyncBlock:1
testSyncMethod:1
... ...
testSyncMethod:99
testSyncBlock:99

鎖(lock)的作用域有兩種,一種是類的對象,另一種的類本身。在以上代碼中給出了兩種使鎖的作用范圍為類的方法,這樣就可以使同一個(gè)類的不同對象之間也能完成同步。
總結(jié)以上,需要注意的有以下幾點(diǎn):
1,wait()、notify()、notifyAll()都需要在擁有對象監(jiān)視器的前提下執(zhí)行,否則就會(huì)拋出java.lang.IllegalMonitorStateException異常。
2,多個(gè)線程可以同時(shí)在一個(gè)對象上等待。
3,notify()是隨機(jī)喚醒一個(gè)在對象上等待的線程,若沒有等待的線程,則什么也不做。
4,notify()喚醒的線程,并不是在notify()執(zhí)行以后就立即喚醒,而是在notify()線程釋放了對象監(jiān)視器之后才真正執(zhí)行被喚醒的線程。
5,Object的這些方法與Thread的sleep、interrupt方法相差還是很遠(yuǎn)的,不要混為一談。

相關(guān)文章

  • SpringCloud超詳細(xì)講解微服務(wù)網(wǎng)關(guān)Zuul

    SpringCloud超詳細(xì)講解微服務(wù)網(wǎng)關(guān)Zuul

    這篇文章主要介紹了SpringCloud Zuul微服務(wù)網(wǎng)關(guān),負(fù)載均衡,熔斷和限流,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-07-07
  • 詳解JAVA高質(zhì)量代碼之?dāng)?shù)組與集合

    詳解JAVA高質(zhì)量代碼之?dāng)?shù)組與集合

      在學(xué)習(xí)編程的過程中,我覺得不止要獲得課本的知識(shí),更多的是通過學(xué)習(xí)技術(shù)知識(shí)提高解決問題的能力,這樣我們才能走在最前方,本文主要講述Java高質(zhì)量代碼之?dāng)?shù)組與集合
    2013-08-08
  • mybatis映射內(nèi)部類的使用及注意事項(xiàng)說明

    mybatis映射內(nèi)部類的使用及注意事項(xiàng)說明

    這篇文章主要介紹了mybatis映射內(nèi)部類的使用及注意事項(xiàng)說明,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • SpringBoot整合Swagger教程詳解

    SpringBoot整合Swagger教程詳解

    SpringBoot是一個(gè)基于Spring框架的輕量級開源框架,它的出現(xiàn)極大地簡化了Spring應(yīng)用的搭建和開發(fā),本文將介紹如何在SpringBoot中使用Swagger來實(shí)現(xiàn)接口文檔的自動(dòng)生成,感興趣的同學(xué)可以參考一下
    2023-04-04
  • 關(guān)于在Java中如何使用yaml的實(shí)例

    關(guān)于在Java中如何使用yaml的實(shí)例

    這篇文章主要介紹了關(guān)于在Java中如何使用yaml的實(shí)例,YAML是一種輕量級的數(shù)據(jù)序列化格式。它以易讀、易寫的文本格式表示數(shù)據(jù),支持列表、字典等各種數(shù)據(jù)結(jié)構(gòu),被廣泛應(yīng)用于配置文件、數(shù)據(jù)傳輸協(xié)議等領(lǐng)域,需要的朋友可以參考下
    2023-08-08
  • Java實(shí)現(xiàn)List去重的方法詳解

    Java實(shí)現(xiàn)List去重的方法詳解

    本文用示例介紹Java的List(ArrayList、LinkedList等)的去重的方法。List去重的常用方法一般是:JDK8的stream的distinct、轉(zhuǎn)為HashSet、轉(zhuǎn)為TreeSet等,感興趣的可以了解一下
    2022-05-05
  • 一文秒懂logstash收集springboot日志的方法

    一文秒懂logstash收集springboot日志的方法

    通過這篇文章帶你了解logstash收集springboot日志的方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-04-04
  • des加密解密JAVA與.NET互通實(shí)例

    des加密解密JAVA與.NET互通實(shí)例

    這篇文章主要介紹了des加密解密JAVA與.NET互通實(shí)例,大家參考使用吧
    2013-12-12
  • 詳解如何保護(hù)SpringBoot配置文件中的敏感信息

    詳解如何保護(hù)SpringBoot配置文件中的敏感信息

    使用過SpringBoot配置文件的朋友都知道,資源文件中的內(nèi)容通常情況下是明文顯示,安全性就比較低一些,所以為了提高安全性,就需要對配置文件中的敏感信息進(jìn)行保護(hù),下面就為大家介紹一下實(shí)現(xiàn)方法吧
    2023-07-07
  • java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(1)

    java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(1)

    下面小編就為大家?guī)硪黄狫ava基礎(chǔ)的幾道練習(xí)題(分享)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧,希望可以幫到你
    2021-07-07

最新評論