1、线程是什么,线程是一份独立运行的程序,有自己专用的运行空间,有可能和其他线程共享一些资源,比如,内存,文件,数据库等。
2、线程同步的概念。当多个线程共同占用一个资源的时候,这时候就要用到线程同步这个概念。线程同步的“同”字可能会让很多人误解,往往会被理解成几个线程一起进行,其实“同”的真正解释是指协同、协助、互相配合。比如说厕所,一个厕所同时只能给一个人占用,当一个人进去的时候,其他人就要在外面等待,里面的人出来以后外面的人才能够进去使用。 再来说说为什么需要线程同步, 最好的例子就是银行的账户,假设你在银行开了一个账户,Account,同时拿到一本存折还有一张银行卡,假设你的银行卡里面有3000大洋。有一天,你和你的女朋友分别拿着银行卡和存折同时在ATM取款机还有银行柜台取钱。两种方式两个线程,共享Account这个账户,假使你用银行卡取钱的时候线程1在操作Account,取出3000,但是在ATM吐出钱而Account还没有扣钱的时候,线程2又启动了,因为线程2并不知道线程1已经取了3000,你的女朋友在柜台又取了3000,这样银行岂不是亏了3000?
public getCash(Account ac, String name, int cash) {
this.ac = ac;
this.cash = cash;
this.name = name;
}
public void run() {
// synchronized (ac) {
int count = ac.getCash(cash);
System.out.println(name + "取了" + count);
// }
}
public Account(int num){
this.total=num;
}
public int getCash(int cash){
if(cash>total){
return -1;
}
else{
disSave(cash);
return cash;
}
}
public static void main(String arg[]) throws Exception{
Account ac=new Account(3000);
getCash thread1=new getCash(ac,"ATM",3000);
getCash thread2=new getCash(ac,"柜台",3000);
thread1.start();
thread2.start();
Thread.sleep(5000);
System.out.println(ac);
}
运行结果:柜台取了3000 ATM取了3000 总共还有金额:-3000
3、然后我们看一下怎么样才能实现线程的同步。
(1)关键字synchronized,我们可以在我们需要共享的资源上加锁,这样就可以保证该对象只能被一个用户使用。
a、synchronized 锁定一个独立的代码块
public void run(){
while(true){
synchronized(lock){
...... //共享资源
}
}
}
上诉代码可以理解为每当执行while里面代码时,共享资源就会被锁定,执行完以后释放锁。
b、synchronized 关键字还可以修饰一个函数
//取钱,够的话扣除然后返回要扣除的钱的总数不够的话返回-1
public synchronized int getCash(int cash){
if(cash>total){
return -1;
} else{
disSave(cash);
return cash;
}
}
同理当使用上面的函数的时候这个函数就会被锁定。
PS: 需要注意的就是synchronized(Lock)里面的Lock必须是公共锁。假如我在Thread1中创建了一个锁lock1,在Thread2也创建了一个锁lock2,那么“上锁”也就没意义了。就好像一个公共教室,我进门锁了门,但是另一个人开了后门从后门进,我锁没锁前门也就没有意义了。
2、看下述代码
private byte[] lock = new byte[0];
public void methodA() {
synchronized(lock) {
…
}
}
使用这种方式生成锁可以称作大神级别的作品,后来查找了下原因,因为生成零长度的byte[]对象只需3条操作码,而Object lock= new Object()则需要7行操作码,所以生成byte[0]是最经济的一种方式。
(2)使用同步锁Lock。Java中有一个包java.util.concurrrent.locks.Lock接口。 具体的使用方法是:
//先生成一个公共锁。
Java.util.concurrent.Lock lock=new java.util.concurrrent.locks.Lock.ReentrantLock();
lock.lock();
//开始上锁
try{
doSomeThing. //共享资源
}
finally{
lock.unlock();
}
synchronized和lock相同与不同: 凡是synchronized能实现的效果lock都是可以实现的,不同的是,lock锁定后执行的内容必须放在try里面,而解锁的unlock必须放finally里面。 当然,同步是要很大的系统开销作为代价的,有时候可能会导致死锁,因此要避免无谓的同步。