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---------");
}</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> m2() { System.out.println(Thread.currentThread().getName() </span>+ " m2 begin---------"<span style="color: #000000;">); </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> { Thread.sleep(</span>5000<span style="color: #000000;">); } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (InterruptedException e) { </span><span style="color: #008000;">//</span><span style="color: #008000;"> TODO Auto-generated catch block</span>
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 </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> run() { t.m1(); } },</span>"t1"<span style="color: #000000;">).start();; </span><span style="color: #0000ff;">new</span> Thread(<span style="color: #0000ff;">new</span><span style="color: #000000;"> Runnable() { @Override </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> run() { t.m2(); } },</span>"t2"<span style="color: #000000;">).start();; }
}
可以看到t1先執行,如果不能同時調用那么t2是不能執行的,必須等t1結束,釋放鎖后才能調用,但這里t2確先執行了,所以是可以同時調用的。
2.對業務寫代碼進行加鎖,對讀代碼不進行加鎖,會產生臟讀
package com.dingyu;public class U {
private String name;
private double banlance;</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">synchronized</span> <span style="color: #0000ff;">void</span> set(String name, <span style="color: #0000ff;">double</span><span style="color: #000000;"> balance) { </span><span style="color: #0000ff;">this</span>.name =<span style="color: #000000;"> name; </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> { Thread.sleep(</span>5000<span style="color: #000000;">); } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (InterruptedException e) { e.printStackTrace(); } </span><span style="color: #0000ff;">this</span>.banlance =<span style="color: #000000;"> balance; } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">double</span><span style="color: #000000;"> getBalance() { </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> banlance; } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> main(String[] args) { U u </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> U(); </span><span style="color: #0000ff;">new</span> Thread(() -> u.set("zhangsan", 500<span style="color: #000000;">)).start(); System.out.println(u.getBalance()); </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> { Thread.sleep(</span>5000<span style="color: #000000;">); } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (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");
}</span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">synchronized</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> m2() { System.out.println(</span>"m2 start"<span style="color: #000000;">); System.out.println(</span>"m2 end"<span style="color: #000000;">); } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> main(String[] args) { I i </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> I(); </span><span style="color: #0000ff;">new</span> Thread(() -><span style="color: #000000;"> i.m1()).start(); }
}
4.模擬一個簡單的死鎖
package com.dingyu;public class DeadLock {
private Object o1 = new Object();
private Object o2 = new Object();</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> m1() { </span><span style="color: #0000ff;">synchronized</span><span style="color: #000000;"> (o1) { </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> { Thread.sleep(</span>10000<span style="color: #000000;">); } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (InterruptedException e) { e.printStackTrace(); } </span><span style="color: #0000ff;">synchronized</span><span style="color: #000000;"> (o2) { System.out.println(</span>"如果出現這句話表示沒有死鎖"<span style="color: #000000;">); } } } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> m2() { </span><span style="color: #0000ff;">synchronized</span><span style="color: #000000;">(o2) { </span><span style="color: #0000ff;">synchronized</span><span style="color: #000000;"> (o1) { System.out.println(</span>"如果出現這句話表示沒有死鎖"<span style="color: #000000;">); } } } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> main(String[] args) { DeadLock deadLock</span>=<span style="color: #0000ff;">new</span><span style="color: #000000;"> DeadLock(); </span><span style="color: #0000ff;">new</span> Thread(()-><span style="color: #000000;">deadLock.m1()).start(); </span><span style="color: #0000ff;">new</span> Thread(()-><span style="color: #000000;">deadLock.m2()).start(); }
}
5.如果執行同步方法中出現異常,那么就會自動釋放鎖,如果不想釋放鎖,加上try catch
package com.dingyu;public class ReleaseLock {
private int count = 0;
private int i = 0;</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">synchronized</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> m1() { </span><span style="color: #0000ff;">while</span> (<span style="color: #0000ff;">true</span><span style="color: #000000;">) { System.out.println(Thread.currentThread().getName() </span>+ " " + count++<span style="color: #000000;">); </span><span style="color: #0000ff;">if</span> (count % 10 == 0<span style="color: #000000;">) i </span>= 1 / 0<span style="color: #000000;">; } } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> main(String[] args) { ReleaseLock releaseLock </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> ReleaseLock(); </span><span style="color: #0000ff;">new</span> Thread(() -> releaseLock.m1(), "t1"<span style="color: #000000;">).start(); </span><span style="color: #0000ff;">new</span> Thread(() -> releaseLock.m1(), "t2"<span style="color: #000000;">).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;</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> m1() { System.out.println(</span>"m1 start"<span style="color: #000000;">); </span><span style="color: #0000ff;">while</span><span style="color: #000000;"> (running) { } System.out.println(</span>"m1 end"<span style="color: #000000;">); } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> main(String[] args) { VolatileDemo volatileDemo </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> VolatileDemo(); </span><span style="color: #0000ff;">new</span> Thread(() -><span style="color: #000000;"> volatileDemo.m1()).start(); </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> { Thread.sleep(</span>1000<span style="color: #000000;">); } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (InterruptedException e) { e.printStackTrace(); } volatileDemo.running </span>= <span style="color: #0000ff;">false</span><span style="color: #000000;">; }
}
7.voliatile 不能保證原子性 不能替換synchronized
package com.dingyu;/**
- voliatile 不能保證原子性 不能替換synchronized
- @author dingyu
*/
public class VolatileDemo02 {
public volatile int count = 0;</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> m1() { </span><span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">int</span> i = 0; i <= 10000; i++<span style="color: #000000;">) count</span>++<span style="color: #000000;">; } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> main(String[] args) { VolatileDemo02 volatileDemo02 </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> VolatileDemo02(); </span><span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">int</span> i = 0; i < 3; i++<span style="color: #000000;">) { </span><span style="color: #0000ff;">new</span> Thread(() -><span style="color: #000000;"> volatileDemo02.m1()).start(); } </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> { Thread.sleep(</span>5000<span style="color: #000000;">); } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (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();</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> m1() { </span><span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">int</span> i = 0; i < 100; i++<span style="color: #000000;">) { count.incrementAndGet(); </span><span style="color: #008000;">//</span><span style="color: #008000;">兩個原子類的方法之間不具備原子性</span>
count.incrementAndGet();
} }
}
9.原子類的不具備可見性
package com.dingyu;import java.util.concurrent.atomic.AtomicBoolean;
public class AtomicDemo02 {
public AtomicBoolean running = new AtomicBoolean(true);</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> m1() { </span><span style="color: #0000ff;">while</span><span style="color: #000000;"> (running.get()) { } } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> main(String[] args) { AtomicDemo02 demo02 </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> AtomicDemo02(); </span><span style="color: #0000ff;">new</span> Thread(()-><span style="color: #000000;">demo02.m1()).start(); demo02.running.set(</span><span style="color: #0000ff;">false</span><span style="color: #000000;">); }
}
10.鎖是鎖在堆內存的那個對象上,而不是引用
package com.dingyu;/**
- 鎖是鎖在堆內存的那個對象上,而不是引用
- @author dingyu
*/
public class ChangeReference {
public Object o = new Object();</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> m1() { </span><span style="color: #008000;">//</span><span style="color: #008000;">鎖o</span> <span style="color: #0000ff;">synchronized</span><span style="color: #000000;"> (o) { </span><span style="color: #0000ff;">while</span> (<span style="color: #0000ff;">true</span><span style="color: #000000;">) { </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> { Thread.sleep(</span>1000<span style="color: #000000;">); } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()); } } } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> main(String[] args) { ChangeReference changeReference </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> ChangeReference(); </span><span style="color: #0000ff;">new</span> Thread(() -> changeReference.m1(), "t1").start();<span style="color: #008000;">//</span><span style="color: #008000;">啟動一個線程 叫t1</span> <span style="color: #0000ff;">try</span><span style="color: #000000;"> { Thread.sleep(</span>3000<span style="color: #000000;">); } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (InterruptedException e) { e.printStackTrace(); } changeReference.o </span>= <span style="color: #0000ff;">new</span> Object();<span style="color: #008000;">//</span><span style="color: #008000;">引用變了</span> <span style="color: #0000ff;">new</span> Thread(() -> changeReference.m1(),"t2").start();<span style="color: #008000;">//</span><span style="color: #008000;">啟動線程 t2</span>
}
}
11.不要鎖字符串常量
package com.dingyu; /** * 不要鎖字符串常量 * @author dingyu * */ public class SynchronizedString { private String s1 = "hello"; private String s2 = "hello";</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> m1() { </span><span style="color: #0000ff;">synchronized</span><span style="color: #000000;"> (s1) { </span><span style="color: #0000ff;">while</span>(<span style="color: #0000ff;">true</span><span style="color: #000000;">) {} } } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> m2() { </span><span style="color: #0000ff;">synchronized</span><span style="color: #000000;"> (s2) { System.out.println(</span>"m2 start"<span style="color: #000000;">); } } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> main(String[] args) { SynchronizedString synchronizedString </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> SynchronizedString(); </span><span style="color: #0000ff;">new</span> Thread(()-><span style="color: #000000;">synchronizedString.m1()).start(); </span><span style="color: #0000ff;">new</span> Thread(()-><span style="color: #000000;">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();</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> m1() { </span><span style="color: #0000ff;">synchronized</span><span style="color: #000000;"> (lock) { System.out.println(</span>"m1 start"<span style="color: #000000;">); </span><span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">int</span> i = 0; i < 10; i++<span style="color: #000000;">) { count</span>++<span style="color: #000000;">; System.out.println(count); </span><span style="color: #0000ff;">if</span> (count == 5<span style="color: #000000;">) { lock.notify(); </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> { lock.wait(); } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (InterruptedException e) { e.printStackTrace(); } } } } } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> m2() { </span><span style="color: #0000ff;">synchronized</span><span style="color: #000000;"> (lock) { System.out.println(</span>"m2 start"<span style="color: #000000;">); </span><span style="color: #0000ff;">if</span> (count != 5<span style="color: #000000;">) { </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> { System.out.println(</span>"m2 在等着 但把鎖釋放了"<span style="color: #000000;">); lock.wait(); } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (InterruptedException e) { e.printStackTrace(); } } System.out.println(</span>"m2 end"<span style="color: #000000;">); lock.notify(); } } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> main(String[] args) { WaitAndNotyifyDemo waitAndNotyifyDemo </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> WaitAndNotyifyDemo(); </span><span style="color: #0000ff;">new</span> Thread(() -><span style="color: #000000;"> waitAndNotyifyDemo.m2()).start(); </span><span style="color: #0000ff;">new</span> Thread(() -><span style="color: #000000;"> waitAndNotyifyDemo.m1()).start(); }
}