这里提到的锁其实就是关键字Synchronized,,它作用是实现线程间的同步,使得每一次只有一个线程进入同步块,保证线程间的安全性。
关键词Synchronized三种基本用法:
给定对象加锁,只有获得锁的线程才能访问该同步块代码
作用于实例方法:给当前实例加锁,获得该实例的才能访问该同步代码块
作用于静态方法:相当于对当前类加锁,获得当前类锁才能访问该代码块。
想要做一个计数器累加直到200,这时候用两个线程会出现对方法内的i值反复读写,读到还不是最新的数据,所以就算每一个线程都加了100次还是不能到200,如果加了对象锁,一次只让一个线程进入读写操作,就能保证数据安全性了,看下解决方式代码:
public class AccoutSync implements Runnable {
static AccoutSync instance=new AccoutSync();
static int i=0;
@Override
public void run() {
for(int j=0;j<100;j++){
synchronized (instance){
i++;
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1=new Thread(instance);
Thread t2=new Thread(instance);//这里注意要获得同一个类实例对象
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
}
i++这段代码一次只允许一个线程进入读写,因此保证了代码安全性
synchronized作用于实例方法:
结果一致
这里讲一下join的小知识,因为我们线程写在main主线程,如果我们不写join等待,那么i的输出为0或者是很小的数值,因为还有等里面线程执行完,main线程已经输出值并结束,一个线程:t1.join();的意思是,其他的线程必须等它执行完才轮到下一个线程。所以平时在主线程写线程需要注意main结束后里面的所有线程也会结束。
注意:获得的对象必须为同一个对象,如果不是无法保证线程同步性,除非加锁的方法是静态方法,此时无论获得本类哪一个对象调用该静态方法总是该类这就是直接对类加锁,需要大家温习下静态方法调用的知识哈。
另外在线程中尽量避免使用HashMap,ArrayList,因为它是线程不安全的,尽量使用vector