方法锁形式: synchronized 修饰普通方法, 锁对象默认为 this ,也就是当前实例对象
注意如果是 不同 类锁的 不同 的同步代码块。情况是有点特殊的,虽然也是有顺序了。
package com.my.com.my.sysnc;
/**
* 同步锁测试
*/
public class TestSynchronized implements Runnable{
static TestSynchronized instance=new TestSynchronized();
Object lock1=new Object();
Object lock2=new Object();
@Override
public void run() {
synchronized (lock1){
System.out.println("lock1对象锁代码块,线程名"+Thread.currentThread().getName());
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"结束lock1");
}
synchronized (lock2){
System.out.println("lock2对象锁代码块,线程名"+Thread.currentThread().getName());
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"结束lock2");
}
}
public static void main(String[] args) {
Thread thread1=new Thread(instance);
Thread thread2=new Thread(instance);
thread1.start();
thread2.start();
}
}
结果 即 ,在run 方法里面, 当 第一个线程执行完 第一个同步代码块的时候,在开始执行第一个代码块的时候。
此时 第二个线程会去执行第一个同步代码块。 这样就有 点并行执行了
:
lock1对象锁代码块,线程名Thread-0
Thread-0结束lock1
lock2对象锁代码块,线程名Thread-0
lock1对象锁代码块,线程名Thread-1
Thread-0结束lock2
Thread-1结束lock1
lock2对象锁代码块,线程名Thread-1
Thread-1结束lock2
类锁
如果是对象锁的话,那么不同的对象对于不同的线程来说,就不会起到 锁的作用了。
如果是 类锁的话,那么就可以做到 不同的对象对于不同的线程 起到 锁的作用。
普通方法: 即非 静态方法
抛出异常的适合, LOCK 锁不会释放锁,而 synchronized 会释放锁
面试题
1. 两个线程同时访问一个对象的同步方法:
能够锁住,同一个实例
2. 两个线程访问的是两个对象的同步方法。
因为不同的实例所有并没有锁的作用,锁对象不是同一个
3. 两个线程访问的是 synchronized 的静态方法
锁的是 class对象, 锁住
4. 同时访问同步方法与非同步方法
同步方法不能影响 非同步方法。
同步方法与非同步方法可以同时运行
5. 访问同一个对象的不同的普通同步方法
方法不能同时的运行。 锁的是同一个对象。受锁的影响
例子:
package com.my.com.my.sysnc;
/**
* 同步锁测试
*/
public class TestSynchronized implements Runnable{
static TestSynchronized instance=new TestSynchronized();
@Override
public void run() {
if (Thread.currentThread().getName().equals("Thread-0")){
test1();
}else{
test2();
}
}
public synchronized void test1(){
System.out.println("对象锁代码块"+Thread.currentThread().getName());
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"结束线程");
}
public synchronized void test2(){
System.out.println("对象锁代码块"+Thread.currentThread().getName());
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"结束线程");
}
public static void main(String[] args) {
Thread thread1=new Thread(instance);
Thread thread2=new Thread(instance);
thread1.start();
thread2.start();
}
}
锁的是同一个实例,竞争的是同一个实例,所以受到影响
可能的结果 :
对象锁代码块Thread-1
Thread-1结束线程
对象锁代码块Thread-0
Thread-0结束线程
6. 同时访问静态 synchronized 和 非静态 synchronized 方法
锁不其作用,两个方法都可以一起运行。
因为静态锁的是 class 对象,非静态的 锁的是 实例对象。是不一样的
package com.my.com.my.sysnc;
/**
* 同步锁测试
*/
public class TestSynchronized implements Runnable{
static TestSynchronized instance=new TestSynchronized();
Object lock1=new Object();
Object lock2=new Object();
@Override
public void run() {
if (Thread.currentThread().getName().equals("Thread-0")){
test1();
}else{
test2();
}
}
public static synchronized void test1(){
System.out.println("静态加锁方法1,,对象锁代码块"+Thread.currentThread().getName());
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"结束线程");
}
public synchronized void test2(){
System.out.println("非静态加锁方法2,对象锁代码块"+Thread.currentThread().getName());
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"结束线程");
}
public static void main(String[] args) {
Thread thread1=new Thread(instance);
Thread thread2=new Thread(instance);
thread1.start();
thread2.start();
}
}
结果:
非静态加锁方法2,对象锁代码块Thread-1
静态加锁方法1,,对象锁代码块Thread-0
Thread-0结束线程
Thread-1结束线程
7. 方法抛异常后,会释放锁
package com.my.com.my.sysnc;
/**
* 同步锁测试
*/
public class TestSynchronized implements Runnable{
static TestSynchronized instance=new TestSynchronized();
Object lock1=new Object();
Object lock2=new Object();
@Override
public void run() {
if (Thread.currentThread().getName().equals("Thread-0")){
test1();
}else{
test2();
}
}
public synchronized void test1(){
System.out.println("对象锁代码块"+Thread.currentThread().getName());
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 抛出异常后,释放锁,由JVM处理释放锁
throw new RuntimeException("抛出异常");
}
public synchronized void test2(){
System.out.println("对象锁代码块"+Thread.currentThread().getName());
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"结束线程");
}
public static void main(String[] args) {
Thread thread1=new Thread(instance);
Thread thread2=new Thread(instance);
thread1.start();
thread2.start();
}
}
结果:
对象锁代码块Thread-0
对象锁代码块Thread-1
Exception in thread "Thread-0" java.lang.RuntimeException: 抛出异常
at com.my.com.my.sysnc.TestSynchronized.test1(TestSynchronized.java:36)
at com.my.com.my.sysnc.TestSynchronized.run(TestSynchronized.java:17)
at java.lang.Thread.run(Thread.java:748)
Thread-1结束线程
性质
1, 可重入:避免死锁,提升封装性
指的是 同一线程的外层函数获得锁之后,内层函数可以之间再次获取该锁
同一个方法可重入(比如递归调用),
不要求同一个方法也可以重入(比如同一个类中调用2个都是锁的方法) ,
可重入不要求 是同一个类中的(子类的 重写父类的加锁方法,并调用父类的加锁方法)
2,不可中断
3. 粒度
线程而非调用
以上来自慕课网