锁保证了多个线程访问一个类时,表现的是正确行为,即保证了线程安全。
synchronized: 可以在任意对象及方法加上锁,而加锁的这段代码称为互斥区或临界区
当多个线程访问synchronized修饰的方法锁,会以按cpu的分配先后顺序,以排队的形式进行处理。
而在这个过程中,线程都会不断地尝试去获得这个锁,如果拿到了,就进入synchronized代码体内容;
拿不到时,还会继续尝试去获取这把锁,直到拿到为止(锁竞争)。
锁的级别有对象锁和类锁
多个线程,每个线程都可以拿到自己指定的锁,分别获得锁之后,执行synchronized方法体的内容。
而关键字synchronized取得的锁都是对象锁,所以两个不同对象,可以获得不同的锁,互不影响。
如下代码为对象锁,因为两个线程都可以拿到自己的锁,所以输出结果并不是唯一的
可能得到的结果有:
thread1 1 thread2 2
thread2 thread1 1 2
thread1 thread2 21
public class Test {
public int a = 0;
public synchronized void t(int i){
a=i;
System.out.println("thread"+i);
System.out.println(a);
}
public static void main(String[] args) throws InterruptedException{
Test test1 = new Test();
Test test2 = new Test();
Thread thread1 = new Thread(new Runnable() {
public void run() {
test1.t(1);
}
});
Thread thread2 = new Thread(new Runnable() {
public void run() {
test2.t(2);
}
});
thread1.start();
thread2.start();
}
}
但是,当在静态方法static中加上synchronized的时候,当前的锁就是类锁,独占一类(.class)的锁。
如下代码就是一个类锁,当一个线程获得这个锁,其他线程都需要等待其结束,其结果为
thread1
1
thread2
2
public class Test {
public static int a = 0;
public static synchronized void t(int i){
a=i;
System.out.println("thread"+i);
System.out.println(a);
}
public static void main(String[] args) throws InterruptedException{
Test test1 = new Test();
Test test2 = new Test();
Thread thread1 = new Thread(new Runnable() {
public void run() {
test1.t(1);
}
});
Thread thread2 = new Thread(new Runnable() {
public void run() {
test2.t(2);
}
});
thread1.start();
thread2.start();
}
}
对象锁的同步与异步
同步:synchronized
同步的概念就是共享,同步的目的是为了线程安全,需要满足原子性及可见性
异步:asychronized
异步的概念就是独立,相互间不受制约。
如:
A线程先持有对象的锁,b线程如果想要访问synchronized修饰的方法,需要等待,这就是同步
A线程先持有对象的锁,b线程可以访问非synchronized修饰的方法,这就是异步
如下代码为同步示例,thread1对象,在获得method1中的对象锁后,无法再立刻获得method2中的对象锁,必须在运行完method1中同步块代码后,释放锁,才能获得新的锁。所以,一个对象只能获得一个锁。
如果把method2中的代码块的锁去掉,那么这时候,线程会进行异步操作,无需等待method1中的sleep方法结束。
public class thread1 {
public void method1() {
synchronized (this) {
System.out.println("t1");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void method2() {
synchronized (this) {
System.out.println("t2");
}
}
public static void main(String[] args) {
thread1 thread1 = new thread1();
Thread thread11 = new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
thread1.method1();
}
});
Thread thread12 = new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
thread1.method2();
}
});
thread11.start();
thread12.start();
}
}