首先要知道锁是个什么东西,做什么用的;它的关键字是synchronized,英文翻译是‘同步的‘,没错,锁就是来控制同步的;为什么要控制同步呢,在多线程的情况下,都需要进入某个单例类中的一个方法,这时就得控制它们一个个的进入才行,否则几个线程同时进入方法体,后进的改变了参数,导致先进的线程中数据混乱;
我们可以把锁想象成接力棒,下一个选手要能够开始跑,那他必须拿到前一个人递给他的接力棒才能跑;锁也是这样,如果一个线程先进了方法体,并且锁住了,后续的线程只能在外面等待,等到前一个进程执行结束释放锁;
/**
* Created by zelei.fan on 2017/7/23.
*/
public class test implements Runnable{
private static int index = 10;
public synchronized void synchronizeMethod(){
if(index > 0){
System.out.println(Thread.currentThread().getName()+":"+index);
index--;
}
}
@Override
public void run() {
/*同步方法,虽然是处理同一个静态变量,但是如果有多个实例线程来访问该方法的时候并不能锁住该方法,
* 不影响其他实例线程在同一时刻访问该方法,线程不安全
* */
synchronizeMethod();
}
public static void main(String[] args) {
test test1 = new test();
new Thread(test1).start();
new Thread(test1).start();
new Thread(test1).start();
new Thread(test1).start();
new Thread(test1).start();
new Thread(test1).start();
new Thread(test1).start();
new Thread(test1).start();
new Thread(test1).start();
new Thread(test1).start();
}
}
Thread-1:10
Thread-6:9
Thread-2:8
Thread-4:7
Thread-5:6
Thread-0:5
Thread-7:4
Thread-3:3
Thread-8:2
Thread-9:1
可以看到锁定方法后,数据没有混乱,每个线程取到的数没有相同的;但是要注意这是有前提的,该方法所在的类必须是单例才行,也就是在整个内存中只有一个实例,如果是多例的话数据就有问题了,下面我换成两个实例来访问:
public static void main(String[] args) {
test test = new test();
test test1 = new test();
new Thread(test).start();
new Thread(test1).start();
new Thread(test).start();
new Thread(test1).start();
new Thread(test).start();
new Thread(test1).start();
new Thread(test).start();
new Thread(test1).start();
new Thread(test).start();
new Thread(test1).start();
}
Thread-0:10
Thread-2:9
Thread-1:10
Thread-3:7
Thread-5:6
Thread-6:6
Thread-8:4
Thread-4:3
Thread-7:3
Thread-9:1
线程0和线程1取到的数时相同,这种情况是线程不安全的;
所以当锁定方法时test的实例调用该方法则会形成互斥,实现线程同步;但是test的另一个实例可以任意的访问该方法,因为不是同一个实例;当某个线程获取到锁时,等到该线程执行完后才会释放锁
但是如果说,当前这个类就是需要多例的,那怎么实现同步呢,很简单,只要加上static就行了;让它变成静态方法,因为静态方法在初始化的时候就已经编译好了放在内存中,而且就只有这一个,不管所在类是不是多例;
/**
* Created by zelei.fan on 2017/7/23.
*/
public class test implements Runnable{
private static int index = 10;
/*同步static方法*/
public static synchronized void synchronizeStatic(){
if(index > 0){
System.out.println(Thread.currentThread().getName()+":"+index);
index--;
}
}
@Override
public void run() {
/*同步方法,虽然是处理同一个静态变量,但是如果有多个实例线程来访问该方法的时候并不能锁住该方法,
* 不影响其他实例线程在同一时刻访问该方法,线程不安全
* */
synchronizeStatic();
}
public static void main(String[] args) {
test test = new test();
test test1 = new test();
new Thread(test).start();
new Thread(test1).start();
new Thread(test).start();
new Thread(test1).start();
new Thread(test).start();
new Thread(test1).start();
new Thread(test).start();
new Thread(test1).start();
new Thread(test).start();
new Thread(test1).start();
}
}
Thread-2:10
Thread-4:9
Thread-6:8
Thread-0:7
Thread-3:6
Thread-7:5
Thread-5:4
Thread-9:3
Thread-8:2
Thread-1:1
从结果可以看到就算是多例,也不会导致数据的混乱;
这时就会有疑问了,锁定方法的时候,锁定对象是方法,锁定个代码块的时候拿什么当锁呢,可以通过锁定一个变量,或者常量,或者是一个实例变量;
/**
* Created by zelei.fan on 2017/7/23.
*/
public class test implements Runnable{
private static int index = 10;
private static final String Lock = "lock";/*常量*/
private byte[] bytes = new byte[0];/*实例变量*/
private String lock = "synchronized";/*成员变量*/
public void synchronizeObject(){
/*通过锁定一个变量,或者常量,或者是一个实例变量*/
synchronized (lock){
if (index > 0){
System.out.println(Thread.currentThread().getName()+":"+index);
index--;
}
}
}
@Override
public void run() {
/*同步方法,虽然是处理同一个静态变量,但是如果有多个实例线程来访问该方法的时候并不能锁住该方法,
* 不影响其他实例线程在同一时刻访问该方法,线程不安全
* */
synchronizeObject();
}
public static void main(String[] args) {
test test = new test();
test test1 = new test();
new Thread(test).start();
new Thread(test1).start();
new Thread(test).start();
new Thread(test1).start();
new Thread(test).start();
new Thread(test1).start();
new Thread(test).start();
new Thread(test1).start();
new Thread(test).start();
new Thread(test1).start();
}
}
Thread-0:10
Thread-4:9
Thread-2:8
Thread-8:7
Thread-5:6
Thread-1:5
Thread-6:4
Thread-9:3
Thread-3:2
Thread-7:1
Thread-6:10
Thread-1:10
Thread-5:8
Thread-9:7
Thread-3:6
Thread-0:5
Thread-2:4
Thread-7:3
Thread-4:2
Thread-8:1
Thread-0:10
Thread-1:9
Thread-2:8
Thread-3:7
Thread-9:6
Thread-5:5
Thread-4:4
Thread-6:3
Thread-7:2
Thread-8:1
结合上面案例,比较实用的就锁定静态方法或者是锁定静态常量;