当前位置: 首页 > >

Java 多线程同步的五种方法

发布时间:

1. 同步方法


public class Bank {
private int count = 0;// 账户余额

// 存钱
public synchronized void addMoney(int money) {
count += money;
System.out.println(System.currentTimeMillis() + "存进:" + money);
}

// 取钱
public synchronized void subMoney(int money) {
if (count - money < 0) {
System.out.println("余额不足");
return;
}
count -= money;
System.out.println(+System.currentTimeMillis() + "取出:" + money);
}

// 查询
public void lookMoney() {
System.out.println("账户余额:" + count);
}
}

?


2. 同步代码块


public class Bank {
private int count = 0;// 账户余额

// 存钱
public void addMoney(int money) {
synchronized(this){
count += money;
}

System.out.println(System.currentTimeMillis() + "存进:" + money);
}

// 取钱
public void subMoney(int money) {
synchronized(this){
if (count - money < 0) {
System.out.println("余额不足");
return;
}
count -= money;
}

System.out.println(+System.currentTimeMillis() + "取出:" + money);
}

// 查询
public void lookMoney() {
System.out.println("账户余额:" + count);
}
}

注:同步是一种高开销的操作,因此应该尽量减少同步的内容。通常没有必要同步整个方法,使用synchronized代码块同步关键代码即可。


3. Volatile


public class Bank {
private volatile int count = 0;// 账户余额

// 存钱
public void addMoney(int money) {
count += money;
System.out.println(System.currentTimeMillis() + "存进:" + money);
}

// 取钱
public void subMoney(int money) {
if (count - money < 0) {
System.out.println("余额不足");
return;
}
count -= money;
System.out.println(System.currentTimeMillis() + "取出:" + money);
}

// 查询
public void lookMoney() {
System.out.println("账户余额:" + count);
}
}

运行结果:



因为volatile不能保证原子操作导致的,因此volatile不能代替 synchronized。此外volatile会组织编译器对代码优化。它的原理是每次要线程要访问volatile修饰 的变量时都是从内存中读取,而不是存缓存当中读取,因此每个线程访问到的变量值都是一样的。这样就保证了同步。


4. 使用重入锁实现线程同步


public class Bank {
private int count = 0;// 账户余额

// 需要声明这个锁
private Lock lock = new ReentrantLock();

// 存钱
public void addMoney(int money) {
lock.lock();
try {
count += money;
System.out.println(System.currentTimeMillis() + "存进:" + money);
} finally {
lock.unlock();
}
}

// 取钱
public void subMoney(int money) {
lock.lock();
try {

if (count - money < 0) {
System.out.println("余额不足");
return;
}
count -= money;
System.out.println(+System.currentTimeMillis() + "取出:" + money);
} finally {
lock.unlock();
}
}

// 查询
public void lookMoney() {
System.out.println("账户余额:" + count);
}
}


1、ReentrantLock()还可以通过public ReentrantLock(boolean fair)构造方法创建公*锁,即,优先运行等待时间最长的线程,这样大幅度降低程序运行效率。

--------------------------------------------------------------------------------------------


5. ThreadLocal


ThreadLocal 类的常用方法


public class Bank {
private static ThreadLocal count = new ThreadLocal(){
@Override
protected Integer initialValue() {
// TODO Auto-generated method stub
return 0;
}
};


// 存钱
public void addMoney(int money) {
count.set(count.get()+money);
System.out.println(System.currentTimeMillis() + "存进:" + money);
}

// 取钱
public void subMoney(int money) {
if (count.get() - money < 0) {
System.out.println("余额不足");
return;
}
count.set(count.get()- money);
System.out.println(+System.currentTimeMillis() + "取出:" + money);
}

// 查询
public void lookMoney() {
System.out.println("账户余额:" + count.get());
}
}

运行结果:只让存,不让取



ThreadLocal的原理:

ThreadLocal与同步机制

ThreadLocal并不能替代同步机制,两者面向的问题领域不同。

?参考:https://blog.csdn.net/hard_working1/article/details/52760729



转载于:https://www.cnblogs.com/zeroingToOne/p/9554560.html



友情链接: 时尚网 总结汇报 幼儿教育 小学教育 初中学习资料网