第三章 線程基本概念(三)

1. volatile關鍵字

可以保證在多線程環境下聲明瞭volatile的變量的可見性,即一個線程修改了改變的值,其他變量能夠看到修改後的結果,但是它不能代替鎖,即保證不了原子性。下面的代碼計算i的值,每個線程計數10000,但是10個線程都執行完,卻始終少於100000。

public class PlusV {
    private static volatile int i=0;
    public static class PlusTask implements Runnable {
        @Override
        public void run() {
            for(int k=0; k<10000; k++) {
                i++;
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread[] threads = new Thread[10];
        for(int i=0; i<10; i++) {
            threads[i] = new Thread(new PlusTask());
            threads[i].start();
        }
        // 讓這10個線程都運行結束
        for(int i=0; i<10; i++) {
            threads[i].join();
        }
        System.out.println(i);
    }
}

2. 線程組

將相同功能的線程放置在一個線程組中,可以輕鬆處理幾十個上百個線程。好的習慣是在往線程組中添加線程的時候最好將線程的名稱描述清楚。

public class ThreadGroupName implements Runnable{
    public static void main(String[] args) {
        ThreadGroup tg = new ThreadGroup("PrintGroup");
        Thread t1 = new Thread(tg, new ThreadGroupName(), "T1");
        Thread t2 = new Thread(tg, new ThreadGroupName(), "T2");
        t1.start();
        t2.start();
        System.out.println(tg.activeCount());// 活動線程的總數
        tg.list();// 打印這個線程組中所有線程的信息
    }
    @Override
    public void run() {
        String groupAndName = Thread.currentThread().getThreadGroup().getName() + "-" + Thread.currentThread().getName();
        while(true) {
            System.out.println("I am " + groupAndName);
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

3. 守護線程(Daemon)

特點是當所有的用戶線程都執行結束後,守護線程也會自動退出執行。

public class DaemonDemo {
    public static class DaemonT extends Thread {
        @Override
        public void run() {
            while(true) {
                System.out.println("I am alive");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Thread t = new DaemonT();
        t.setDaemon(true);// 將線程設置成守護線程
        t.start();
        Thread.sleep(2000);
    }
}

4. 線程優先級

Java優先級1-10,但是通常使用1,5,10。高優先級的線程更傾向於先執行結束。

public class PriorityDemo {
    public static class HightPriority extends Thread {
        static int count = 0;

        public void run() {
            while (true) {
                synchronized (PriorityDemo.class) {
                    count++;
                    if (count > 10000000) {
                        System.out.println("HightPriority is complete");
                        break;
                    }
                }
            }
        }
    }

    public static class LowPriority extends Thread {
        static int count = 0;

        public void run() {
            while (true) {
                synchronized (PriorityDemo.class) {
                    count++;
                    if (count > 10000000) {
                        System.out.println("LowPriority is complete");
                        break;
                    }
                }
            }
        }
    }

    public static void main(String[] args) {
        Thread high = new HightPriority();
        Thread low = new LowPriority();
        high.setPriority(Thread.MAX_PRIORITY);
        low.setPriority(Thread.MIN_PRIORITY);
        low.start();
        high.start();
    }
}

5. synchronized實現線程間同步

對需要線程同步執行的代碼加鎖,從而使得每次只能有一個線程進入同步代碼塊,進而保證線程的安全性。

指定加鎖對象:對給定對象加鎖,進入同步代碼塊前獲得對象的鎖。

public class AccountingSync implements Runnable {
    private static AccountingSync instance = new AccountingSync();
    static volatile int i = 0;

    public void increase() {
        i++;
    }

    @Override
    public void run() {
        for (int j = 0; j < 10000000; j++) {
            synchronized (instance) {
                increase();
            }
        }
    }

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

直接作用在實例方法上:相當於對當前實例加鎖,進入同步代碼塊需要獲得當前實例的鎖。

public class AccountingSync2 implements Runnable {
    private static AccountingSync2 instance = new AccountingSync2();
    static volatile int i = 0;

    public synchronized void increase() {
        i++;
    }

    @Override
    public void run() {
        for (int j = 0; j < 10000000; j++) {
                increase();
        }
    }

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

直接作用與靜態方法:相當於對當前類加鎖,進入同步代碼塊前要獲得當前類的鎖。

public class AccountingSyncClass implements Runnable{
    static int i = 0;
    public static synchronized  void increase() {
        i++;
    }

    @Override
    public void run() {
        for (int j=0; j<10000000; j++) {
            increase();
        }
    }

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

下一章 多線程中隱蔽的錯誤:https://blog.csdn.net/qq_35165775/article/details/107118559

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章