Java馬士兵高並發編程視頻學習筆記(一)


1.同一個資源,同步和非同步的方法可以同時調用

package com.dingyu;

public class Y {
    public synchronized void m1() {
        System.out.println(Thread.currentThread().getName() + " m1 begin---------");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + " m1 end---------");
    }

    public void m2() {
        System.out.println(Thread.currentThread().getName() + " m2 begin---------");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + " m2 end---------");
    }
    public static void main(String[] args) {
        Y t = new Y();
//        new Thread(()->t.m1(),"t1").start();
//        new Thread(()->t.m2(),"t2").start();
        new Thread(new Runnable() {
            
            @Override
            public void run() {
                t.m1();
                
            }
        },"t1").start();;
    new Thread(new Runnable() {
            
            @Override
            public void run() {
                t.m2();
                
            }
        },"t2").start();;
    }
}

 

 

可以看到t1先執行,如果不能同時調用那么t2是不能執行的,必須等t1結束,釋放鎖后才能調用,但這里t2確先執行了,所以是可以同時調用的。

2.對業務寫代碼進行加鎖,對讀代碼不進行加鎖,會產生臟讀

  

package com.dingyu;

public class U {
    private String name;
    private double banlance;

    public synchronized void set(String name, double balance) {
        this.name = name;
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        this.banlance = balance;
    }

    public double getBalance() {
        return banlance;
    }

    public static void main(String[] args) {
        U u = new U();
        new Thread(() -> u.set("zhangsan", 500)).start();
        System.out.println(u.getBalance());
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(u.getBalance());
    }
}

3.同線程內一個同步方法可以去調用另一個同步方法(重入鎖 還有一種重入鎖就是子類調用父類的同步方法)

package com.dingyu;

public class I {
    public synchronized void m1() {
        System.out.println("m1 start");
        m2();
        System.out.println("m1 end");
    }

    private synchronized void m2() {
        System.out.println("m2 start");
        System.out.println("m2 end");
    }

    public static void main(String[] args) {
        I i = new I();
        new Thread(() -> i.m1()).start();
    }

}

4.模擬一個簡單的死鎖

package com.dingyu;

public class DeadLock {
    private Object o1 = new Object();
    private Object o2 = new Object();

    public void m1() {
        synchronized (o1) {
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
            synchronized (o2) {
                System.out.println("如果出現這句話表示沒有死鎖");
            }
        }
        
    }
    
    public void m2() {
        synchronized(o2) {
            
            synchronized (o1) {
                System.out.println("如果出現這句話表示沒有死鎖");
            }
            
        }
        
    }
    public static void main(String[] args) {
        DeadLock deadLock=new DeadLock();
        new Thread(()->deadLock.m1()).start();
        new Thread(()->deadLock.m2()).start();
    }
}

5.如果執行同步方法中出現異常,那么就會自動釋放鎖,如果不想釋放鎖,加上try catch

package com.dingyu;

public class ReleaseLock {
    private int count = 0;
    private int i = 0;

    public synchronized void m1() {
        while (true) {
            System.out.println(Thread.currentThread().getName() + " " + count++);
            if (count % 10 == 0)
                i = 1 / 0;
        }
    }

    public static void main(String[] args) {
        ReleaseLock releaseLock = new ReleaseLock();
        new Thread(() -> releaseLock.m1(), "t1").start();
        new Thread(() -> releaseLock.m1(), "t2").start();
    }
}

 6.volatile關鍵字(無鎖同步)

volatile關鍵字 每個線程都有自己的一小塊內存,執行的時候會把變量copy過來,修改了后在寫回對象,

執行m1方法的線程把 running讀到內存里,與此同時主線程也把running讀到內存,並進行修改,寫回對象為false

但是執行m1的線程里的內存一直都是true啊(因為太忙了沒空去刷新)所以會形成死循環,

volatile就是當running改了之后 *立馬去通知其他線程,你們記得去主存刷新一下,一刷新,running為false,退出while循環。

package com.dingyu;
/**
 * volatile關鍵字   每個線程都有自己的一小塊內存,執行的時候會把變量copy過來,修改了后在寫回對象,
 * 執行m1方法的線程把 running讀到內存里,與此同時主線程也把running讀到內存,並進行修改,寫回對象為false
 * 但是執行m1的線程里的內存一直都是true啊(因為太忙了沒空去刷新)所以會形成死循環,volatile就是當running改了之后
 * 立馬去通知其他線程,你們記得去主存刷新一下,一刷新,running為false,退出while循環。
 * @author dingyu
 *
 */
public class VolatileDemo {
    private volatile boolean running = true;

    public void m1() {
        System.out.println("m1 start");
        while (running) {
            
        }
        System.out.println("m1 end");
    }

    public static void main(String[] args) {
        VolatileDemo volatileDemo = new VolatileDemo();
        new Thread(() -> volatileDemo.m1()).start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        volatileDemo.running = false;

    }
}

7.voliatile 不能保證原子性 不能替換synchronized

package com.dingyu;

/**
 * voliatile 不能保證原子性 不能替換synchronized
 * 
 * @author dingyu
 *
 */
public class VolatileDemo02 {
    public volatile int count = 0;

    public void m1() {
        for (int i = 0; i <= 10000; i++)
            count++;
    }

    public static void main(String[] args) {
        VolatileDemo02 volatileDemo02 = new VolatileDemo02();
        for (int i = 0; i < 3; i++) {
            new Thread(() -> volatileDemo02.m1()).start();
        }
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(volatileDemo02.count);
    }
}

 8.多個原子類的方法之間不具備原子性

package com.dingyu;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * 原子類 具有原子性,但兩個原子類的方法之間不具備原子性
 * 
 * @author dingyu
 *
 */
public class AtomicDemo {
    private AtomicInteger count = new AtomicInteger();

    public void m1() {
        for (int i = 0; i < 100; i++) {            
            count.incrementAndGet();
            //兩個原子類的方法之間不具備原子性
            count.incrementAndGet();
        
        }
    }
}

9.原子類的不具備可見性

package com.dingyu;

import java.util.concurrent.atomic.AtomicBoolean;

public class AtomicDemo02 {
    public AtomicBoolean running = new AtomicBoolean(true);

    public void m1() {
        while (running.get()) {

        }
    }

    public static void main(String[] args) {
        AtomicDemo02 demo02 = new AtomicDemo02();
        new Thread(()->demo02.m1()).start();
        demo02.running.set(false);
    }
}

10.鎖是鎖在堆內存的那個對象上,而不是引用

package com.dingyu;

/**
 * 鎖是鎖在堆內存的那個對象上,而不是引用
 * 
 * @author dingyu
 *
 */
public class ChangeReference {
    public Object o = new Object();

    public void m1() {
        //鎖o
        synchronized (o) {
            while (true) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName());
            }
        }
    }

    public static void main(String[] args) {
        ChangeReference changeReference = new ChangeReference();
        new Thread(() -> changeReference.m1(), "t1").start();//啟動一個線程 叫t1
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        changeReference.o = new Object();//引用變了
        new Thread(() -> changeReference.m1(),"t2").start();//啟動線程 t2
    }
}

 

 11.不要鎖字符串常量

package com.dingyu;
/**
 * 不要鎖字符串常量
 * @author dingyu
 *
 */
public class SynchronizedString {
    private String s1 = "hello";
    private String s2 = "hello";

    public void m1() {
        synchronized (s1) {
            while(true) {}
        }
    }

    public void m2() {
        synchronized (s2) {
            System.out.println("m2 start");
        }
    }

    public static void main(String[] args) {
        SynchronizedString synchronizedString = new SynchronizedString();
        new Thread(()->synchronizedString.m1()).start();
        new Thread(()->synchronizedString.m2()).start();
    }
}

12.wait 讓線程暫停,釋放鎖, notify 喚醒線程,不釋放鎖

package com.dingyu2;

/**
 * wait 讓線程暫停,釋放鎖, notify 喚醒線程,不釋放鎖
 * 
 * @author dingyu
 *
 */
public class WaitAndNotyifyDemo {
    private volatile int count = 0;
    private Object lock = new Object();

    public void m1() {
        synchronized (lock) {
            System.out.println("m1 start");
            for (int i = 0; i < 10; i++) {
                count++;
                System.out.println(count);
                if (count == 5) {
                    lock.notify();
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }

        }
    }

    public void m2() {
        synchronized (lock) {
            System.out.println("m2 start");
            if (count != 5) {
                try {
                    System.out.println("m2 在等着 但把鎖釋放了");
                    lock.wait();                    
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("m2 end");
            lock.notify();
        }
    }

    public static void main(String[] args) {
        WaitAndNotyifyDemo waitAndNotyifyDemo = new WaitAndNotyifyDemo();
        new Thread(() -> waitAndNotyifyDemo.m2()).start();
        new Thread(() -> waitAndNotyifyDemo.m1()).start();
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM