以前一直没有养成一个梳理知识的习惯,今天复习到多线程的知识的,想到的经典的存钱取钱多线程同步机制,今天在这里梳理下,错的地方请各位大佬指正
1:使用synchronized关键字修饰方法和代码块(这就是两种了)
2:使用特殊变量volatitle关键字修饰
3:JAVA5.0引入了重入锁机制
package testThread;
import org.omg.CORBA.PUBLIC_MEMBER;
import org.w3c.dom.css.Counter;
/**
* 一本正经的假装银行
*
*/
public class Bank {
//账户余额
private int sum=0;
/**
* 存钱
* @param money
*/
public synchronized void addMoney(int money) {
sum+=money;
System.out.println(System.currentTimeMillis()+"存进"+money);
}
/**
* 取钱
*/
public void subMoney(int money)
{
if(sum-money<0)
{
System.out.println("余额不足");
return;
}else {
sum-=money;
System.out.println(System.currentTimeMillis()+"取出"+money);
}
}
/**
* 查询余额
*/
public void lookMoney()
{
System.out.println("账户余额"+sum);
}
}
package testThread;
/**
* 主方法完成.假装两个存钱和取钱的的(大佬有钱,一直存取)
*/
public class TestMain {
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();
}
}
});
Thread tsub = new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
bank.subMoney(100);
bank.lookMoney();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
tsub.start();
tadd.start();
}
}
结果分析:我电脑CPU处理的太快了,一直没看到真正想要的结果真实的结果类似这个
余额不足 账户余额:0 余额不足 账户余额:100 (有一百你不让我取,这个货) 1441792010959存进:100 账户余额:100
package testThread;
import org.omg.CORBA.PUBLIC_MEMBER;
import org.w3c.dom.css.Counter;
/**
* 假装银行
*
*/
public class Bank {
//账户余额
private int sum=0;
/**
* 存钱
* @param money
*/
public synchronized void addMoney(int money) {
sum+=money;
System.out.println(System.currentTimeMillis()+"存进"+money);
}
/**
* 取钱
*/
public synchronized void subMoney(int money)
{
if(sum-money<0)
{
System.out.println("余额不足");
return;
}else {
sum-=money;
System.out.println(System.currentTimeMillis()+"取出"+money);
}
}
/**
* 查询余额
*/
public void lookMoney()
{
System.out.println("账户余额"+sum);
}
}
咳咳,其实是上面的图...........懂就好(synchronized 当然也可以修饰静态的方法,不过调用它的时候会封锁整个类);
package testThread;
import org.omg.CORBA.PUBLIC_MEMBER;
import org.w3c.dom.css.Counter;
/**
* 假装银行
*
*/
public class Bank {
//账户余额
private int sum=0;
/**
* 存钱
* @param money
*/
public void addMoney(int money) {
synchronized(this)
{
sum+=money;
System.out.println(System.currentTimeMillis()+"存进"+money);
}
}
/**
* 取钱
*/
public void subMoney(int money)
{
synchronized(this)
{
if(sum-money<0)
{
System.out.println("余额不足");
return;
}else {
sum-=money;
System.out.println(System.currentTimeMillis()+"取出"+money);
}
}
}
/**
* 查询余额
*/
public void lookMoney()
{
System.out.println("账户余额"+sum);
}
}
结果和上面的一样
package testThread;
/**
* 假装
*
*/
public class Bank {
//账户余额
private volatile int sum=0;
/**
* 存钱
* @param money
*/
public void addMoney(int money) {
sum+=money;
System.out.println(System.currentTimeMillis()+"存进"+money);
}
/**
* 取钱
*/
public void subMoney(int money)
{
if(sum-money<0)
{
System.out.println("余额不足");
return;
}else {
sum-=money;
System.out.println(System.currentTimeMillis()+"取出"+money);
}
}
/**
* 查询余额
*/
public void lookMoney()
{
System.out.println("账户余额"+sum);
}
}
余额不足 账户余额:0 余额不足 账户余额:100 1441792010959存进:100 账户余额:100 1441792011960取出:100 账户余额:0 1441792011961存进:100 账户余额:100
结果又tmd不让取了,,这个是为啥呢
因为volatitle不能保证原子操作导致,每次线程要访问volatitle变量都是从内存中去读的,而是不是从缓存中读的,这就保证每个线程访问的变量是一样的,这就保证了同步
啥也不说,老规矩,上代码
package testThread;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Bank{
//账户余额
private int sum=0;
//1.1: 我们需要先申明这个锁
private Lock lock=new ReentrantLock();
/**
* 存钱
* @param money
*/
public void addMoney(int money) {
//1.2上锁
lock.lock();
try {
sum+=money;
System.out.println(System.currentTimeMillis()+"存进"+money);
} catch (Exception e) {
// TODO: handle exception
}finally{
//1.3解锁
lock.unlock();
}
}
/**
* 取钱
*/
public void subMoney(int money)
{
//1.1上锁
lock.lock();
try {
if(sum-money<0)
{
System.out.println("余额不足");
return;
}else {
sum-=money;
System.out.println(System.currentTimeMillis()+"取出"+money);
}
} finally{
//接锁
lock.unlock();
}
}
/**
* 查询余额
*/
public void lookMoney()
{
System.out.println("账户余额"+sum);
}
}
和上上图结果一样,不贴了,老铁....
我们一般同步用synchronized,如果你想要用高级一点的,用lock,但别忘了释放一下,不理会发生死锁的哦,同学