java实现线程同步的总结

要实现线程同步的原因:
java允许多线程并发控制,当多个线程同时操作一个可共享的资源变量时,
会产生冲突,使得变量值不唯一,因此我们需要加入同步锁来避免在当前线程的操作未完成前,其它线程改变共享资源值的情况发生,从而保证变量的唯一
性和准确性

方法

  • synchronized
    synchronized可以修饰方法,但是由于同步本身就是一种高开销的操作,因此我们应该尽可能的减少同步的内容,提高性能
    使用同步代码块,下面的方式
 synchronized (this){
                    if (account.getBalance() > money) {
                        System.out.println(Thread.currentThread().getName() + "取钱" + money + "成功");
                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                        account.reduceBalance(money);
                        System.out.println("\t" + Thread.currentThread().getName() + "成功后的余额: " + account.getBalance());
                    } else {
                        System.out.println(Thread.currentThread().getName() + "取钱失败");
                        System.out.println("\t" + Thread.currentThread().getName() + "失败后的余额: " + account.getBalance());
                        break;
                    }
                }
  • volatile
    volatile关键字保证了每个线程所取得的共享资源变量的值是一样的,它的原理是被volatile修饰的变量被访问时,都会从内存中读取,而不是从缓存(寄存器)中,这样保证了每个线程访问到的变量值的一致性
    但是他不会保证操作的原子性,
 private volatile double balance;
  • java.util.concurrent包下的ReentrantLock类
    使用的方法
//需要声明这个锁
private Lock lock = new ReentrantLock();

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

}finally{
lock.unlock();//解锁
}
}

Lock与Synchronized的对比:
主要相同点:Lock能完成Synchronized所实现的所有功能。
主要不同点:Lock有比Synchronized更好的性能。Synchronized会自动释放锁,但是Lock一定要求程序员手工释放,并且必须在finally从句中释放。
synchronized 修饰方法时 表示同一个对象在不同的线程中 表现为同步队列
如果实例化不同的对象 那么synchronized就不会出现同步效果了。
这个地方不理解可以看这篇博文
https://blog.csdn.net/jzy23682891/article/details/7197115

  • ThreadLocal
    如果使用ThreadLocal管理变量,则每一个使用该变量的线程都获得该变量的副本,副本之间相互独立,这样每一个线程都可以随意修改自己的变量副本,而不会对其他线程产生影响。现在明白了吧,原来每个线程运行的都是一个副本,也就是说存钱和取钱是两个账户,知识名字相同而已。
    这样的话当操作不一致的时候,就无法解决问题,会出现下面的结果
public class Bank {

private static ThreadLocal<Integer> count = new ThreadLocal<Integer>(){
@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());
}
}
package threadTest;


public class SyncThreadTest {

public static void main(String args[]){
final Bank bank=new Bank();

Thread tadd=new Thread(new Runnable() {

@Override
public void run() {
// TODO Auto-generated method stub
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
bank.addMoney(100);
bank.lookMoney();
System.out.println("\n");

}
}
});

Thread tsub = new Thread(new Runnable() {

@Override
public void run() {
// TODO Auto-generated method stub
while(true){
bank.subMoney(100);
bank.lookMoney();
System.out.println("\n");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
tsub.start();

tadd.start();
}
}

结果:

余额不足
账户余额:0


余额不足
1502547748383存进:100
账户余额:100
账户余额:0




余额不足
账户余额:0


1502547749383存进:100
账户余额:200

用例参考:
https://www.cnblogs.com/jiansen/p/7351872.html

猜你喜欢

转载自blog.csdn.net/qq_32635069/article/details/79907963