java synchronized的初步理解
本博客每一个小标题下的内容独立且完整,如只是想了解某个小标题下的内容,只需前往看该小标题即可。
1. 多线程并发访问同一个对象的同一个非静态synchronized方法
完整代码:
public class myClass {
public static void main(String[] args) {
final TestClass testClass = new TestClass();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
testClass.methodA();
}
}, "线程1");
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
testClass.methodA();
}
}, "线程2");
thread1.start();
thread2.start();
}
}
class TestClass {
/**
* 普通同步方法A
*/
public void methodA() {
synchronized (this) {
for (int i = 0; i < 4; i++) {
System.out.println(Thread.currentThread().getName() + "正在执行methodA:" + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
小标题已经准确表达了上面这块代码的意思,运行结果如下:
同一个对象同一个非静态同步方法.png由执行结果可知,两个线程中其中一个线程执行完才会执行第二个线程。结论就是,多个线程并发访问同一个对象的同一个非静态synchronized方法时,先获取到锁的线程执行完毕后才会执行其它线程。也就是说synchronized(this)
这种锁可以锁定一个非静态synchronized方法,只让获取了该锁的线程执行,其它线程在该线程未执行完毕之前不能执行
2. 多线程并发访问同一个对象的不同非静态synchronized方法
完整代码:
public class myClass {
public static void main(String[] args) {
final TestClass testClass = new TestClass();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
testClass.methodA();
}
}, "线程1");
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
testClass.methodB();
}
}, "线程2");
thread1.start();
thread2.start();
}
}
class TestClass {
/**
* 普通同步方法A
*/
public void methodA() {
synchronized (this) {
for (int i = 0; i < 4; i++) {
System.out.println(Thread.currentThread().getName() + "正在执行methodA:" + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 普通同步方法B
*/
public void methodB() {
synchronized (this) {
for (int i = 0; i < 4; i++) {
System.out.println(Thread.currentThread().getName() + "正在执行methodB:" + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
运行结果如下:
同一个对象不同非静态同步方法.png由执行结果可知,两个线程中其中一个线程执行完才会执行第二个线程。结论是多个线程并发访问同一个对象的不同非静态synchronized方法时,先获取到锁的线程执行完毕后才会执行其它线程。也就是说,synchronized(this)
这种锁锁定的范围是该对象的所有非静态synchronized方法,而不单单是获取了该锁的线程正在执行的非静态synchronized方法
3. 多线程并发访问同一个对象的不同方法,一个是非静态synchronized方法,一个是非静态非synchronized方法
完整代码:
public class myClass {
public static void main(String[] args) {
final TestClass testClass = new TestClass();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
testClass.methodA();
}
}, "线程1");
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
testClass.methodC();
}
}, "线程2");
thread1.start();
thread2.start();
}
}
class TestClass {
/**
* 普通同步方法A
*/
public void methodA() {
synchronized (this) {
for (int i = 0; i < 4; i++) {
System.out.println(Thread.currentThread().getName() + "正在执行methodA:" + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 普通方法,非同步
*/
public void methodC() {
for (int i = 0; i < 4; i++) {
System.out.println(Thread.currentThread().getName() + "正在执行methodC:" + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
运行结果如下:
同一个对象一个非静态同步方法一个非静态非同步方法.png由执行结果可知,两个线程并发执行,没有先后顺序。结论是多个线程并发访问同一个对象的不同方法时,一个是非静态synchronized方法,一个是非静态非synchronized方法,这两线程并发运行。也就是说,synchronized(this)
这种锁锁定的是该对象的所有非静态synchronized方法,并不会锁定该对象的非静态非synchronized方法。
4. 多线程并发访问同一个对象的不同方法,一个是非静态synchronized方法,一个是静态synchronized方法
public class myClass {
public static void main(String[] args) {
final TestClass testClass = new TestClass();
// final TestClass testClassNext = new TestClass();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
testClass.methodA();
}
}, "线程1");
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
testClass.methodE();
}
}, "线程2");
thread1.start();
thread2.start();
}
}
class TestClass {
/**
* 普通同步方法A
*/
public void methodA() {
synchronized (this) {
for (int i = 0; i < 4; i++) {
System.out.println(Thread.currentThread().getName() + "正在执行methodA:" + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 静态同步方法E
*/
public synchronized static void methodE() {
for (int i = 0; i < 4; i++) {
System.out.println(Thread.currentThread().getName() + "正在执行methodE:" + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
运行结果如下:
同一个对象一个静态同步方法一个非静态同步方法.png由执行结果可知,两个线程并发执行,没有先后顺序。结论是多个线程并发访问同一个对象的不同方法时,一个是非静态synchronized方法,另一个是静态synchronized方法,这两线程并发运行。也就是说,,synchronized(this)
这种锁锁定的范围是这个对象所有的非静态synchronized方法,而静态synchronized锁锁定的是该类的所有对象的所有静态synchronized方法,两个锁锁的作用范围不一样,执行起来就不会相互锁定
5. 多线程并发访问同一个类不同对象的同一个非静态synchronized方法
public class myClass {
public static void main(String[] args) {
final TestClass testClass = new TestClass();
final TestClass testClassNext = new TestClass();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
testClass.methodA();
}
}, "线程1");
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
testClassNext.methodA();
}
}, "线程2");
thread1.start();
thread2.start();
}
}
class TestClass {
/**
* 普通同步方法A
*/
public void methodA() {
synchronized (this) {
for (int i = 0; i < 4; i++) {
System.out.println(Thread.currentThread().getName() + "正在执行methodA:" + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
运行结果如下:
不同对象同一个非静态同步方法.png由执行结果可知,两个线程并发执行,没有先后顺序。结论是多个线程并发访问同一个类不同对象的同一个非静态synchronized方法时,这两线程并发运行。也就是说,synchronized(this)
这种锁锁定的范围是该对象的非静态synchronized方法,而不能锁定该类的另一个实例的非静态synchronized方法。
6. 多线程并发访问同一个类的不同对象的同一个静态synchronized方法
public class myClass {
public static void main(String[] args) {
final TestClass testClass = new TestClass();
final TestClass testClassNext = new TestClass();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
testClass.methodD();
}
}, "线程1");
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
testClassNext.methodD();
}
}, "线程2");
thread1.start();
thread2.start();
}
}
class TestClass {
/**
* 静态同步方法D
*/
public synchronized static void methodD() {
for (int i = 0; i < 4; i++) {
System.out.println(Thread.currentThread().getName() + "正在执行methodD:" + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
运行结果如下:
不同对象同一个静态同步方法.png由执行结果可知,两个线程中其中一个线程执行完才会执行第二个线程。结论是多线程并发访问同一个类的不同对象的同一个静态synchronized方法时,先获取到锁的线程执行完毕之后才会执行下一个线程。也就是说,静态synchronized锁锁定的范围已经不再是单个对象的静态synchronized方法了,而是所有对象的静态synchronized方法。
上述所有情况的总结
-
在一个类对象范围内,非静态synchronized锁不仅锁定当前获取该锁的线程正在执行的非静态synchronized方法,还会锁定该对象的其他所有非静态synchronized方法,但不会锁定该对象的非静态非synchronized方法、静态非synchronized方法和静态synchronized方法;
-
非静态synchronized锁作用范围是在一个对象里,并不会干涉到其他线程调用该类的另一个对象的非静态synchronized方法,而静态synchronized锁可以影响到其它对象;
-
静态synchronized锁会锁定该类的所有对象的所有静态synchronized方法,但不会锁定该类的所有对象的的静态非synchronized方法、非静态synchronized方法、非静态非synchronized方法;
-
非静态synchronized锁锁定的是该类的一个实例对象,静态synchronized锁锁定的其实是该类的Class对象。