高并发编程系列(一)
High concurrency programming series
对某个对象加锁
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);
}
}
}
等同于在方法的代码执行时要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);
}
}
任何线程执行下面代码,必须要拿到this 的锁,
记住锁定的时对象 不是代码块 表面看着是代码块
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);
}
}
}
放在静态方法上面,由于静态没有this可以锁定,不需要new 出对象,运用了反射.
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();
}
});*/
}
}
对业务写方法加锁.
对业务读方法不加锁.
容易产生脏读问题(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("掌上编程"));
}
}
一个同步方法可以调用另外一个同步方法,一个线程已经拥有某个对象,再次申请的时候仍然会得到该对象的锁,
也就是说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");
}
}
一个同步的方法可以调用另外一个同步方法.一个线程已经拥有某个对象的锁,再次申请的时候仍然会得到该对象的锁.也就是说 synchronized获得的锁是可重入的.这里是继承中有可能发生的情形,子类调用父类的同步方法.
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");
}
}