本篇博客是慕课网Java高并发之魂:synchronized深度解析的笔记
分析:首先是同一个对象,并且是同步方法,这属于对象锁中的普通同步方法锁,效果是线程顺序执行;
public class SynchTest implements Runnable{
static SynchTest synchTest=new SynchTest();
@Override
public void run() {
method();
}
// 同步方法锁
public synchronized void method() {
System.out.println(Thread.currentThread().getName()+" 开始执行");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" 执行完毕");
}
public static void main(String[] args) {
// 两个线程
Thread t1=new Thread(synchTest);
Thread t2=new Thread(synchTest);
t1.start();
t2.start();
while (t1.isAlive() || t2.isAlive()) {
}
System.out.println("finished");
}
}
执行结果
分析:访问不同的对象,如果要实现同步的话,锁的级别应该到类锁,但题中是同步方法,属于对象级别的,所以,不同对象不受干扰,线程并行运行;
public class SynchTest2 implements Runnable{
static SynchTest2 synchTest1=new SynchTest2();
static SynchTest2 synchTest2=new SynchTest2();
@Override
public void run() {
method();
}
// 同步方法锁
public synchronized void method() {
System.out.println(Thread.currentThread().getName()+" 开始执行");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" 执行完毕");
}
public static void main(String[] args) {
// 两个线程,不同对象
Thread t1=new Thread(synchTest1);
Thread t2=new Thread(synchTest2);
t1.start();
t2.start();
while (t1.isAlive() || t2.isAlive()) {
}
System.out.println("finished");
}
}
运行结果:
分析:在上篇文章中提到synchronized修饰的静态方法,锁的级别是类锁,不管是不是同一个对象,线程都是顺序同步执行,synchronized关键字生效;
public class SynchTest2 implements Runnable{
static SynchTest2 synchTest1=new SynchTest2();
static SynchTest2 synchTest2=new SynchTest2();
@Override
public void run() {
method();
}
// 同步静态方法锁
public synchronized static void method() {
System.out.println(Thread.currentThread().getName()+" 开始执行");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" 执行完毕");
}
public static void main(String[] args) {
// 两个线程,不同对象
Thread t1=new Thread(synchTest1);
Thread t2=new Thread(synchTest2);
t1.start();
t2.start();
while (t1.isAlive() || t2.isAlive()) {
}
System.out.println("finished");
}
}
执行结果:
分析:一个线程访问同步方法,一个线程访问非同步方法,两者是否受影响?synchronized影响范围是它修饰的方法体,对其它方法不受影响,结论就是非同步方法不受影响,该怎么运行还怎么运行,即使修饰的是静态方法,也不受影响,因为锁类型不同;
public class SynchTest2 implements Runnable{
static SynchTest2 synchTest=new SynchTest2();
/*
* 如果是线程1直接执行方法1,线程2执行方法2
*/
public void run() {
if("Thread-0".equals(Thread.currentThread().getName())) {
method1();
}else {
method2();
}
}
// 同步方法
public synchronized void method1() {
System.out.println(Thread.currentThread().getName()+" 开始执行同步方法");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" 同步方法执行完毕");
}
// 非同步方法
public void method2() {
System.out.println(Thread.currentThread().getName()+" 开始执行非同步方法");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" 非同步方法执行完毕");
}
public static void main(String[] args) {
// 两个线程,同一对象
Thread t1=new Thread(synchTest);
Thread t2=new Thread(synchTest);
t1.start();
t2.start();
while (t1.isAlive() || t2.isAlive()) {
}
System.out.println("finished");
}
}
运行结果:
分析:有点绕,没办法,面试题经常就是很绕的,最好把面试官也给绕进去算了;同一个对象的两个线程,其中一个线程访问类的同步方法1,另一个线程访问同步方法2,两者受影响吗?普通同步方法默认是(this)对象级别的,锁类型相同,所以,同一个对象的线程访问两个方法是受影响的,顺序执行,不会并行的;
public class SynchTest2 implements Runnable{
static SynchTest2 synchTest=new SynchTest2();
/*
* 如果是线程1直接执行方法1,线程2执行方法2
*/
public void run() {
if("Thread-0".equals(Thread.currentThread().getName())) {
method1();
}else {
method2();
}
}
// 同步方法1
public synchronized void method1() {
System.out.println(Thread.currentThread().getName()+" 开始执行同步方法1");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" 同步方法1执行完毕");
}
// 同步方法2
public synchronized void method2() {
System.out.println(Thread.currentThread().getName()+" 开始执行同步方法2");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" 同步方法2执行完毕");
}
public static void main(String[] args) {
// 两个线程,同一对象
Thread t1=new Thread(synchTest);
Thread t2=new Thread(synchTest);
t1.start();
t2.start();
while (t1.isAlive() || t2.isAlive()) {
}
System.out.println("finished");
}
}
运行结果;
分析:这个情况比较复杂,根据以上结论可以得出,只要两个线程的锁类型相同,就是同步,不相同,则并行,不受干扰!
静态同步方法锁级别是类锁,非静态同步方法级别是对象锁,所以并行,不受干扰的;
public class SynchTest2 implements Runnable{
static SynchTest2 synchTest1=new SynchTest2();
static SynchTest2 synchTest2=new SynchTest2();
/*
* 如果是线程1直接执行方法1,线程2执行方法2
*/
public void run() {
if("Thread-0".equals(Thread.currentThread().getName())) {
method1();
}else {
method2();
}
}
// 静态同步方法
public static synchronized void method1() {
System.out.println(Thread.currentThread().getName()+" 开始执行静态同步方法");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" 静态同步方法执行完毕");
}
// 非静态同步方法
public synchronized void method2() {
System.out.println(Thread.currentThread().getName()+" 开始执行非静态同步方法");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" 非静态同步方法执行完毕");
}
public static void main(String[] args) {
// 两个线程,同一对象
Thread t1=new Thread(synchTest1);
Thread t2=new Thread(synchTest1);
t1.start();
t2.start();
while (t1.isAlive() || t2.isAlive()) {
}
System.out.println("finished");
}
}
执行结果
延伸一下:两个都是静态方法呢?由于都是类锁,不管线程是不是一个对象的,都是顺序执行,同步运作(下个例子就用这个来验证);
对象锁 | 同步代码块锁 | 普通方法锁 |
类锁 | static方法锁 | *.class锁 |
答案是:会自动释放锁,具体原理后续展开讨论;
public class SynchTest2 implements Runnable{
static SynchTest2 synchTest1=new SynchTest2();
static SynchTest2 synchTest2=new SynchTest2();
/*
* 如果是线程1直接执行方法1,线程2执行方法2
*/
public void run() {
if("Thread-0".equals(Thread.currentThread().getName())) {
method1();
}else {
method2();
}
}
// 静态同步方法
public static synchronized void method1() {
System.out.println(Thread.currentThread().getName()+" 开始执行静态同步方法1");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 抛出异常
int num=1/0;
System.out.println(Thread.currentThread().getName()+" 静态同步方法1执行完毕");
}
// 非静态同步方法
public static synchronized void method2() {
System.out.println(Thread.currentThread().getName()+" 开始执行静态同步方法2");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" 静态同步方法2执行完毕");
}
public static void main(String[] args) {
// 两个线程
Thread t1=new Thread(synchTest1);
Thread t2=new Thread(synchTest2);
t1.start();
t2.start();
while (t1.isAlive() || t2.isAlive()) {
}
System.out.println("finished");
}
}
运行结果: