JAVA基礎--Thread多線程簡單應用(2)

上次學習了線程的建立,已級簡單應用,此次來看看線程安全,及同步鎖 synchronized 的做用:java

package thread;

/**
 * Synchronized 同步鎖, 線程安全;
 * 
 * 買票舉例測試
 **/
public class MyTheard3 {
    /**
     * 知識點: 
     * 1, 什麼是線程安全? 
     *  線程安全: 就是當   多個線程 同時共享同一個 全局變量 的時候,作 寫 的操做時,數據的不可控性;
     *  
     * 2, 什麼是線程同步?
     *  線程同步,是爲了保證數據的原子性;保證數據的安全;
     *  
     * 3, 同步鎖: 
     * synchronized(Object) {
     *      包含須要同步的代碼,這個地方一次只能有一個線程執行;
     * }
     * 
     * 4, 同步的前提:
     *  (1), 必需要有兩個或兩個以上的線程;
     *  (2), 必須是多個線程使用同一把鎖;
     *  
     * 5, 同步鎖的做用: 
     *   保證同步中只能有一個線程運行;
     *   
     * 6, 原理: 
     *  (1), 當多個線程同時執行時,若是有一個線程搶到了鎖,那麼該線程執行,其餘線程就算有CPU執行權也要等待,等搶到鎖的線程釋放了鎖後,其餘線程在繼續搶鎖;
     *      (鎖就至關於一個身份令牌,有鎖才能執行,而鎖只有一把)(舉例: 搶廁所)
     *  
     *  (2), 只有當代碼執行完畢,或者拋出異常時,纔會釋放鎖;
     *  
     *  
     * 7, 優勢: 解決了線程安全問題;
     * 
     * 8, 缺點: 須要搶鎖,消耗CPU資源,會發生死鎖問題; 
     * 
     * */
    
    
    
    public static void main(String[] args) {
        // 兩個線程必須使用同一個run()
        Send1 send = new Send1();
        Thread send1 = new Thread(send,"窗口1:");
        Thread send2 = new Thread(send,"窗口2:");
        
        send1.start();
        send2.start();
        
    }
    
    
    
    
    
    
}

/**
 * 售票線程
 * */
class Send1 implements Runnable{
    /*總票數,線程的全局變量*/
    private static int total = 100;
    
    /*線程中的鎖*/
    Object object = new Object();
    
    @Override
    public void run() {
        while(total>0){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            stale();
        }
    }
    
    private void stale(){
        //同步鎖:
        synchronized (object) {
            //每次只能有一個線程執行
            if(total>0){
                System.out.println(Thread.currentThread().getName()+"賣出第"+((100-total)+1)+"張票");
                total--;
            }
        }
    }
    
}

2, 使用this鎖:安全

private void stale(){
        //同步鎖 this :
        synchronized (this) {
            //每次只能有一個線程執行
            if(total>0){
                System.out.println(Thread.currentThread().getName()+"賣出第"+((100-total)+1)+"張票");
                total--;
            }
        }
    }

 

3, 使用同步函數:多線程

//同步函數: (synchronized修飾的方法)
    private synchronized void stale(){
        //每次只能有一個線程執行
        if(total>0){
            System.out.println(Thread.currentThread().getName()+"賣出第"+((100-total)+1)+"張票");
            total--;
        }
    }

4: 同步函數使用的就是this鎖;併發

5: 總結: 同步函數和同步代碼塊能夠實現同步,只要同步代碼塊使用this鎖便可;ide

6: 靜態同步函數:函數

//靜態同步函數:(static synchronized修飾的方法, 使用  Send1.class 鎖)
    private static synchronized void stale2(){
      //每次只能有一個線程執行
        if(total>0){
            System.out.println(Thread.currentThread().getName()+"賣出第"+((100-total)+1)+"張票");
            total--;
        }
    }

靜態同步函數使用 當前類的字節碼 鎖;學習

7: 總結 : 同步函數和靜態同步函數不能實現同步;測試

 

8: 多線程的可見性: volatile;this

package thread;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * 多線程的可見性
 * 
 * */
public class MyTheard4 {
    /**
     * 知識點: 
     * 
     * 1, 多線程的三大特性 : 原子性; 可見性; 有序性; 
     * 
     * 2, 什麼是JAVA內存模型?
     *    JAVA內存模型分爲: 主內存(主要存放共享的全局變量), 私有內存(該線程的私有變量); (屬於 多線程可見性JMM方面)
     *    JAVA內存模型,決定一個線程與另外一個線程是否可見; (線程安全問題)
     *    
     * 3, volatile 可見性;
     * 
     * 4, AtomicInteger (JDK1.5併發包中的);
     * */
    
    
    public static void main(String[] args) {
        TheardTest thread = new TheardTest();
        Thread t1 = new Thread(thread,"T1");
        Thread t2 = new Thread(thread,"T2");
        Thread t3 = new Thread(thread,"T3");
        Thread t4 = new Thread(thread,"T4");
        Thread t5 = new Thread(thread,"T5");
        
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
        
        /**
         * 運行結果: 
         *  T2::1923
         *  T3::2876
         *  T5::3876
         *  T1::1922
         *  T4::4876
         * 結論 : volatile 不能保證原子性;
         * */
        
    }
    
    
    
}

class TheardTest implements Runnable{
    // 線程可見
    private volatile static int count = 0;
    
    @Override
    public void run() {
        for(int i=0;i<1000;i++){
            count++;
        }
        System.out.println(Thread.currentThread().getName()+"count::"+count);
    }
    
}

9: 多線程可見性: AtomicIntegeratom

package thread;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * 多線程的可見性
 * 
 * */
public class MyTheard4 {
    public static void main(String[] args) {
        TheardTest thread = new TheardTest();
        Thread t1 = new Thread(thread,"T1");
        Thread t2 = new Thread(thread,"T2");
        Thread t3 = new Thread(thread,"T3");
        Thread t4 = new Thread(thread,"T4");
        Thread t5 = new Thread(thread,"T5");
        
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
        
    }
  
}

class TheardTest implements Runnable{
    // 線程可見
    private static AtomicInteger count2 = new AtomicInteger(0);
    
    @Override
    public void run() {
        for(int i=0;i<1000;i++){
            //等同於count++
            count2.incrementAndGet();
        }
        System.out.println(Thread.currentThread().getName()+"count2::"+count2);
    }
    
}

測試後,會發現: AtomicInteger能夠保證數據原子性;

10, ThreadLocal 爲每一個線程建立局部變量,私有數據

class TheardTest implements Runnable{
    // 線程可見
    private volatile static int count = 0;
    // 共享數據,保證數據原子性
    private static AtomicInteger count2 = new AtomicInteger(0);
    // ThreadLocal: 爲每一個線程建立局部變量,私有數據
    private static ThreadLocal<Integer> count3 = new ThreadLocal<Integer>(){
        protected Integer initialValue() {
            return 0;
        };
    };
    
    @Override
    public void run() {
        for(int i=0;i<1000;i++){
            count++;
            count2.incrementAndGet();
            count3.set(count3.get()+1);
        }
        System.out.println(Thread.currentThread().getName()+"count::"+count);
        System.out.println(Thread.currentThread().getName()+"count2::"+count2);
        System.out.println(Thread.currentThread().getName()+"count3::"+count3.get());
    }
    
}

從打印結果能夠發現,使用ThreadLocal建立的共享變量並無共享;

相關文章
相關標籤/搜索