线程八锁得到的结论:
- 非静态方法的锁默认为 this, 静态方法的锁为 对应的 Class 实例
- 某一个时刻内,只能有一个线程持有锁,无论几个方法。
论证过程:
1、八锁案例:判断打印的 “one” or “two”
- 两个普通同步方法,两个线程,标准打印, 打印? //one two
public class TestThread8Monitor {
public static void main(String[] args) {
Number number1 = new Number();
new Thread(new Runnable() {
@Override
public void run() {
number1.getOne();
}
},"A").start();
new Thread(new Runnable() {
@Override
public void run() {
number1.getTwo();
}
},"B").start();
}
}
class Number{
public synchronized void getOne(){
System.out.println("one");
}
public synchronized void getTwo(){
System.out.println("two");
}
}
- 新增 Thread.sleep() 给 getOne() ,打印? //one two
public class TestThread8Monitor {
public static void main(String[] args) {
Number number1 = new Number();
new Thread(new Runnable() {
@Override
public void run() {
number1.getOne();
}
},"A").start();
new Thread(new Runnable() {
@Override
public void run() {
number1.getTwo();
}
},"B").start();
}
}
class Number{
public synchronized void getOne(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {}
System.out.println("one");
}
public synchronized void getTwo(){
System.out.println("two");
}
}
- 新增普通方法 getThree() , 打印? //three one two
public class TestThread8Monitor {
public static void main(String[] args) {
Number number1 = new Number();
new Thread(new Runnable() {
@Override
public void run() {
number1.getOne();
}
},"A").start();
new Thread(new Runnable() {
@Override
public void run() {
number1.getTwo();
}
},"B").start();
new Thread(new Runnable() {
@Override
public void run() {
number1.getThree();
}
},"C").start();
}
}
class Number{
public synchronized void getOne(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {}
System.out.println("one");
}
public synchronized void getTwo(){
System.out.println("two");
}
public void getThree(){
System.out.println("three")
}
}
- 两个普通同步方法,两个 Number 对象,打印? //two one
public class TestThread8Monitor {
public static void main(String[] args) {
Number number1 = new Number();
Number number2 = new Number();
new Thread(new Runnable() {
@Override
public void run() {
number1.getOne();
}
},"A").start();
new Thread(new Runnable() {
@Override
public void run() {
number2.getTwo();
}
},"B").start();
}
}
class Number{
public synchronized void getOne(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {}
System.out.println("one");
}
public synchronized void getTwo(){
System.out.println("two");
}
}
- 修改 getOne() 为静态同步方法,一个 Number 对象,打印? //two one
public class TestThread8Monitor {
public static void main(String[] args) {
Number number1 = new Number();
new Thread(new Runnable() {
@Override
public void run() {
number1.getOne();
}
},"A").start();
new Thread(new Runnable() {
@Override
public void run() {
number1.getTwo();
}
},"B").start();
}
}
class Number{
public static synchronized void getOne(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {}
System.out.println("one");
}
public synchronized void getTwo(){
System.out.println("two");
}
}
- 修改两个方法均为静态同步方法,一个 Number 对象? //one two
public class TestThread8Monitor {
public static void main(String[] args) {
Number number1 = new Number();
new Thread(new Runnable() {
@Override
public void run() {
number1.getOne();
}
},"A").start();
new Thread(new Runnable() {
@Override
public void run() {
number1.getTwo();
}
},"B").start();
}
}
class Number{
public static synchronized void getOne(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {}
System.out.println("one");
}
public static synchronized void getTwo(){
System.out.println("two");
}
}
- 一个静态同步方法,一个非静态同步方法,两个 Number 对象? //two one
public class TestThread8Monitor {
public static void main(String[] args) {
Number number1 = new Number();
Number number2 = new Number();
new Thread(new Runnable() {
@Override
public void run() {
number1.getOne();
}
},"A").start();
new Thread(new Runnable() {
@Override
public void run() {
number2.getTwo();
}
},"B").start();
}
}
class Number{
public static synchronized void getOne(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {}
System.out.println("one");
}
public synchronized void getTwo(){
System.out.println("two");
}
}
- 两个静态同步方法,两个 Number 对象? //one two
public class TestThread8Monitor {
public static void main(String[] args) {
Number number1 = new Number();
Number number2 = new Number();
new Thread(new Runnable() {
@Override
public void run() {
number1.getOne();
}
},"A").start();
new Thread(new Runnable() {
@Override
public void run() {
number2.getTwo();
}
},"B").start();
}
}
class Number{
public static synchronized void getOne(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {}
System.out.println("one");
}
public static synchronized void getTwo(){
System.out.println("two");
}
}
2、分析:
-
两个普通同步方法,两个线程,标准打印, 打印? //one two
-
新增 Thread.sleep() 给 getOne() ,打印? //one two
-
新增普通方法 getThree() , 打印? //three one two
-
两个普通同步方法,两个 Number 对象,打印? //two one
-
修改 getOne() 为静态同步方法,一个 Number 对象,打印? //two one
-
修改两个方法均为静态同步方法,一个 Number 对象? //one two
-
一个静态同步方法,一个非静态同步方法,两个 Number 对象? //two one
-
两个静态同步方法,两个 Number 对象? //one two
1 和 2 对比:一个对象里面如果有多个synchronized方法,某一个时刻内,只要一个线程去调用其中的一个synchronized方法了,其它的线程都只能等待,换句话说,某一个时刻内,只能有唯一一个线程去访问这些synchronized方法
所有的非静态同步方法用的都是同一把锁——实例对象本身,也就是说如果一个实例对象的非静态同步方法获取锁后,该实例对象的其他非静态同步方法必须等待获取锁的方法释放锁后才能获取锁,可是别的实例对象的非静态同步方法因为跟该实例对象的非静态同步方法用的是不同的锁,所以毋须等待该实例对象已获取锁的非静态同步方法释放锁就可以获取他们自己的锁。
1 、2 和 3 对比:加个普通方法后发现和同步锁无关
2 和 4 对比:换成两个对象后,不是同一把锁了,情况立刻变化。 锁的是当前对象this,被锁定后,其它的线程都不能进入到当前对象的其它的 synchronized方法。
5 和 6 对比:都换成静态同步方法后,情况又变化
5 和 7 分析对比:情况没有发生改变,说明静态同步方法和非静态同步方法并不是同一把锁。
6 和 8 分析对比:所有的静态同步方法用的也是同一把锁——类对象本身(Object.class),这两把锁是两个不同的对 象,所以静态同步方法与非静态同步方法之间是不会有竞态条件的。但是一旦一个 静态同步方法获取锁后,其他的静态同步方法都必须等待该方法释放锁后才能获取 锁,而不管是同一个实例对象的静态同步方法之间,还是不同的实例对象的静态同 步方法之间,只要它们同一个类的实例对象!