进程是指在内存中运行的应用程序,进程有自己独立的堆和栈,既不共享堆也不共享栈,有自己独立的内存空间,一个进程可以有多个线程。
线程是在进程中执行的一个流程,一个进程可以运行多个线程,线程拥有袭击独立的栈和共享内存,共享堆,不共享栈,标准的线程由操作系统调度。
线程同步的5种方法
1、用synchronized关键字同步方法
由于java中每个对象都有一个内置锁,当用关键字synchronized修饰时内置锁将会保护整个方法,在调用该方法之前,需要获取该内置锁,否则将处于阻塞状态。
2、用synchronized关键字同步代码块、
3、用特殊变量Volatile实现线程同步,
<1>Volatile关键字为域变量的访问提供的一种免锁机制。
<2>用Volatile修饰域,相当于告诉虚拟机,该域可能会被其他线程更新。因此每次使用都要重新计算,而不是用寄存器中的值。
<3>Volatile不能保证任何的原子操作,他不能用来修饰final类型的变量。
Volatile 关键字不能保证线程的安全,此关键字用在多线程同步中,可保证读取的可见性,JVM只是保证从主内存加载到线程工作内存的值是最新读取的,而非cache中,但是在多线程对Volatile的写操作时,无法保证线程安全。例如Thread-1和Thread-2在进行read和load操作时,发现主内存中 的count=5,两个线程T1、T2都会加载到最新的值到线程的工作内存中,然后T1对T1堆count进行修改之后,会write到主内存中,此时主内存总的count值为6,。由于T2此时已经read、load加载count=5加载到T2线程的工作内存中,进行运行之后count值w为6,也会write到主内存中,导致主内存中的count值还是6,因此用Volatile修饰之后,还是会存在多线程并发的问题。
4、用重入锁实现线程的同步
在javaSE5.0中新增加了一个java.util.concurrent包来支持同步。ReentrantLock类可重入、互斥、实现了Lock接口的锁,他和synchronized具有相同的基本行为和语义。ReentrantLock类常有的方法有:ReentrantLock()创建一个ReentrantLock的实例,用lock()获得锁,用unlock释放锁,注:用ReentrantLock还可以用构造器创建公平锁的构造方法,但是由于可能大幅度降低程序运行的效率,一般不推荐使用。使用ReentrantLock要及时释放锁,否则会出现死锁,通常在finally中释放锁。
//用重入锁实现线程同步
public class bank{
private int count = 0;
//创建锁
paivate Lock lock = new ReentranLock();
//存钱
public void addMoney(int money){
lock.lock();//上锁
try{
count +=money
}finally{
lock.unlock;
}
}
//取钱
public void subMoney(int money){
if(count - money > 0){
retrun
}
lock.lock();//上锁
try{
count -=money;
}finally{
lock.unlock();
}
}
//查询
public void showMoney(){
System.out.println("当前的账户余额"+money);
}
}
5、用局部变量实现线程同步,ThreadLocal。
TheadLocal的原理,若使用ThreadLocal来管理变量,则每一个使用该变量的线程都会获得该变量的一个副本,副本之间相互独立,这样每个线程就可以随意独立的改变自己的变量副本,而不会对其他线程造成影响。
class class bank(){
private static ThreadLoacl<Integer> count = new ThreadLocal<Integer>(){
@override
protected Integer initialValue(){
retrun 0;
}
}
//存钱
public void addMoney(int money){
count.set(count.get()+money);
}
//取钱
public void subMoney(){
if(count.get() - money < 0){
return
}
set.count(count.get() - money);
}
//查询
public void showMoey(){
System.out.println(count.get());
}
}
用ThreadLocal修饰来维护变量,每个线程运行的都是一个副本,也就是说,存钱和取钱时连个账户,只是名字相同而已。
ThreadLocal和同步机制
ThreadLocal与同步机制都是用来解决多线程中相同变量的访问冲突的问题。
ThreadLocal是用空间换时间,而同步机制使用时间换空间。