高并發(fā)編程系列(一)
High concurrency programming series
對(duì)某個(gè)對(duì)象加鎖
public class Ta {
/**
* synchronized keyword
* Locks an object
*/
private int count = 10;
private Object o = new Object();
public void m(){
synchronized(o){
count--;
System.out.println(Thread.currentThread().getName() + "count:" + count);
}
}
}
等同于在方法的代碼執(zhí)行時(shí)要synchronized
public class Tb {
/**
* Is equivalent to synchronized when the method's code executes.
*/
private int count = 10;
private Object o = new Object();
public synchronized void m() {
count--;
System.out.println(Thread.currentThread().getName() + "count:" + count);
}
}
任何線程執(zhí)行下面代碼,必須要拿到this 的鎖,
記住鎖定的時(shí)對(duì)象 不是代碼塊 表面看著是代碼塊
public class Tc {
/**
* Any thread that executes the following code must get the lock for this,
* Remember that the object that is locked is not a block of code and it looks like a block of code
*/
private int count = 10;
public void m() {
synchronized(this) {
count--;
System.out.println(Thread.currentThread().getName() + "count:" + count);
}
}
}
放在靜態(tài)方法上面,由于靜態(tài)沒有this可以鎖定,不需要new 出對(duì)象,運(yùn)用了反射.
public class Td {
/**
* On the static method, because static no this can be locked, do not need to new out of the object, the use of reflection.
*/
private static int count = 10;
private Object o = new Object();
public synchronized static void m() {
count--;
System.out.println(Thread.currentThread().getName() + "count:" + count);
}
public void mm() {
synchronized(Td.class) { //考慮一下這里寫 synchronized (this) 是否可以 不可以
count--;
System.out.println(Thread.currentThread().getName() + "count:" + count);
}
}
}
public class Te implements Runnable {
private int count = 10;
@Override
public synchronized void run() {
count --;
System.out.println(Thread.currentThread().getName() + "count:" + count);
}
public static void main(String[] args) {
Te t = new Te();
for (int i = 0; i<5;i++){
new Thread(t,"THREAD" + i).start();
}
}
}
m1不影響m2,同步方法不影響其他方法,m2 不需要鎖.
public class Tf {
/**
*
* M1 does not affect m2, synchronous methods do not affect other methods, and m2 does not need a lock.
*/
public synchronized void m1() {
System.out.println(Thread.currentThread().getName() + "m1.start....");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "m1.end");
}
public void m2() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "m2");
}
public static void main(String[] args) {
Tf t = new Tf();
new Thread(()->t.m1()).start();
new Thread(()->t.m2()).start();
/*new Thread(t::m1,"t1").start();
new Thread(t::m2,"t2").start();*/
/* new Thread(new Runnable() {
@Override
public void run() {
t.m1();
}
});*/
}
}
對(duì)業(yè)務(wù)寫方法加鎖.
對(duì)業(yè)務(wù)讀方法不加鎖.
容易產(chǎn)生臟讀問題(dirtyRead).
public class Tg {
/**
*
* Locks the business write method.
* Business read methods are not locked.
* DirtyRead is easy to produce.
* No two seconds sleep, no problem, plus there's a dirty read on the read,
* there's a block of code between two seconds that might be executed by some other program that's not locked.
* Lock or no lock depends on the business.
* Tg For the account class It has a name and a balance
*
*/
String name;
double balance;
public synchronized void set(String name, double balance) {
this.name = name;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.balance = balance;
}
public /*synchronized*/ double getBalance(String name) {
return this.balance;
}
public static void main(String[] args) {
Tg t = new Tg();
new Thread(()->t.set("掌上編程",100.0)).start();
try{
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(t.getBalance("掌上編程"));
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(t.getBalance("掌上編程"));
}
}
一個(gè)同步方法可以調(diào)用另外一個(gè)同步方法,一個(gè)線程已經(jīng)擁有某個(gè)對(duì)象,再次申請(qǐng)的時(shí)候仍然會(huì)得到該對(duì)象的鎖,
也就是說synchronized 獲得鎖是可重入的耀里。
public class Th {
/**
*
* One synchronized method can call another, and a thread that already owns an object will still get its lock when it requests it again.
* That is, synchronized acquired locks are reentrant.
*/
synchronized void m1() {
System.out.println("m1.start");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
m2();
}
synchronized void m2() {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("m2");
}
}
一個(gè)同步的方法可以調(diào)用另外一個(gè)同步方法.一個(gè)線程已經(jīng)擁有某個(gè)對(duì)象的鎖,再次申請(qǐng)的時(shí)候仍然會(huì)得到該對(duì)象的鎖.也就是說 synchronized獲得的鎖是可重入的.這里是繼承中有可能發(fā)生的情形,子類調(diào)用父類的同步方法.
public class Ti {
synchronized void m() {
System.out.println("m.start");
try{
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("m.end");
}
public static void main(String[] args) {
new TiTi().m();
}
}
class TiTi extends Ti {
@Override
synchronized void m(){
System.out.println("child m start");
super.m();
System.out.println("child m end");
}
}