1、java中的每个实例对象都有一个锁,当访问实例对象的非静态synchronized方法或synchronized(实例对象){*****}时,首先要获取该对象锁才能够执行。
2、java中的每个类 也都有一个锁,当访问静态的类方法或synchronized(类:****.class){},首先要获取该类锁才能够执行
3、实例对象锁和类锁 是两种不同类型的锁,互不影响。
实例场景描述:Main方法启动两个线程,
一个线程处理Person类的useComputer() 都使用完电脑之后,才能一个一个的离开
一个线程处理Person类的leave() 一个一个人的离开
实例代码一:synchronized修饰方法定义,例:public synchronized void useComputer(),表示对当前实例对象加锁
MyThread.java
package browser;
public class MyThread {
public static void main(String[] args) {
Person person = new Person(new Computer());
MyRunnable1 r1 = new MyRunnable1(person);
MyRunnable2 r2 = new MyRunnable2(person);
Thread t1 = new Thread(r1);
t1.setName("t1");
Thread t2 = new Thread(r2);
t2.setName("t2");
t1.start();
t2.start();
}
}
class MyRunnable1 implements Runnable {
private Person person;
public MyRunnable1 (Person person) {
this.person = person;
}
@Override
public void run() {
person.useComputer();
}
}
class MyRunnable2 implements Runnable {
private Person person;
public MyRunnable2 (Person person) {
this.person = person;
}
@Override
public void run() {
person.leave();
}
}
Person.java
package browser;
public class Person {
public Computer computer;
public Person(Computer computer) {
this.computer = computer;
}
/**
* 都使用完电脑之后,才能一个一个的离开
*/
public synchronized void useComputer() {
try {
for(int i=0; i<10; i++) {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + " 第" + i + " person " + computer.playMovie());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void leave() {
try {
for(int i=0; i<10; i++) {
Thread.sleep(500);
System.out.println(Thread.currentThread().getName() + " 第" + i + " " + computer.finished());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Computer.java
package browser;
public class Computer {
public String playMovie() {
return "computer playing movie";
}
public String finished() {
return "computer finished";
}
}
执行结果:
t1 第0 person computer playing movie
t1 第1 person computer playing movie
t1 第2 person computer playing movie
t1 第3 person computer playing movie
t1 第4 person computer playing movie
t1 第5 person computer playing movie
t1 第6 person computer playing movie
t1 第7 person computer playing movie
t1 第8 person computer playing movie
t1 第9 person computer playing movie
t2 第0 computer finished
t2 第1 computer finished
t2 第2 computer finished
t2 第3 computer finished
t2 第4 computer finished
t2 第5 computer finished
t2 第6 computer finished
t2 第7 computer finished
t2 第8 computer finished
t2 第9 computer finished
可以看出,因为person对象的两个方法都加了synchronized关键字,所以t2线程必须得等到t1线程执行完成之后再执行。
实例代码二:synchronized加载代码块内部,修饰成员变量,表示的是对成员变量对象加锁,而不是对当前类对象加锁
MyThread.java
package browser;
public class MyThread {
public static void main(String[] args) {
Person person = new Person(new Computer());
MyRunnable1 r1 = new MyRunnable1(person);
MyRunnable2 r2 = new MyRunnable2(person);
Thread t1 = new Thread(r1);
t1.setName("t1");
Thread t2 = new Thread(r2);
t2.setName("t2");
t1.start();
t2.start();
}
}
class MyRunnable1 implements Runnable {
private Person person;
public MyRunnable1 (Person person) {
this.person = person;
}
@Override
public void run() {
person.useComputer();
}
}
class MyRunnable2 implements Runnable {
private Person person;
public MyRunnable2 (Person person) {
this.person = person;
}
@Override
public void run() {
person.leave();
}
}
Person.java
package browser;
public class Person {
public Computer computer;
public Person(Computer computer) {
this.computer = computer;
}
/**
* 排队使用电脑,一个使用完后另一个才使用
*/
public void useComputer() {
try {
synchronized (computer) { //修饰成员变量computer,表示对computer对象加锁,而不是当前类对象
for(int i=0; i<10; i++) {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + " 第" + i + " person " + computer.playMovie());
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void leave() {
try {
for(int i=0; i<10; i++) {
Thread.sleep(500);
System.out.println(Thread.currentThread().getName() + " 第" + i + " " + computer.finished());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
computer.java
package browser;
public class Computer {
public String playMovie() {
return "computer playing movie";
}
public String finished() {
return "computer finished";
}
}
执行结果:
t2 第0 computer finished
t1 第0 person computer playing movie
t2 第1 computer finished
t2 第2 computer finished
t1 第1 person computer playing movie
t2 第3 computer finished
t2 第4 computer finished
t1 第2 person computer playing movie
t2 第5 computer finished
t2 第6 computer finished
t1 第3 person computer playing movie
t2 第7 computer finished
t2 第8 computer finished
t1 第4 person computer playing movie
t2 第9 computer finished
t1 第5 person computer playing movie
t1 第6 person computer playing movie
t1 第7 person computer playing movie
t1 第8 person computer playing movie
t1 第9 person computer playing movie
可以看出,synchronized(computer)后, 当线程1睡眠时,线程2仍然能够访问person对象的leave方法。所以,synchronized(computer)是对Computer对象加锁,而不是对Person对象加锁。synchronized(this)则表示对当前对象加锁。
从另一个角度,也可以证明synchronize(computer)是对Computer对象加锁,再Computer对象的finishied方法声明中加上synchronized,代码如下:Computer.java
package browser;
public class Computer {
public String playMovie() {
return "computer playing movie";
}
public synchronized String finished() {
return "computer finished";
}
}
执行结果:
t1 第0 person computer playing movie
t1 第1 person computer playing movie
t1 第2 person computer playing movie
t1 第3 person computer playing movie
t1 第4 person computer playing movie
t1 第5 person computer playing movie
t1 第6 person computer playing movie
t1 第7 person computer playing movie
t1 第8 person computer playing movie
t1 第9 person computer playing movie
t2 第0 computer finished
t2 第1 computer finished
t2 第2 computer finished
t2 第3 computer finished
t2 第4 computer finished
t2 第5 computer finished
t2 第6 computer finished
t2 第7 computer finished
t2 第8 computer finished
t2 第9 computer finished
可以看出,两个线程已经得到了同步。
static synchronized表示对 类加锁,而不是对象,两种类型的锁,互不影响。实例如下:
只修改Person.java代码即可
package browser;
public class Person {
public Computer computer;
public Person(Computer computer) {
this.computer = computer;
}
/**
* 排队使用电脑,一个使用完后另一个才使用
*/
public static synchronized void useComputer() {
try {
for(int i=0; i<10; i++) {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + " 第" + i + " person ");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void leave() {
try {
for(int i=0; i<10; i++) {
Thread.sleep(500);
System.out.println(Thread.currentThread().getName() + " 第" + i + " " + computer.finished());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
执行结果:
t2 第0 computer finished
t1 第0 person
t2 第1 computer finished
t2 第2 computer finished
t1 第1 person
t2 第3 computer finished
t2 第4 computer finished
t1 第2 person
t2 第5 computer finished
t2 第6 computer finished
t1 第3 person
t2 第7 computer finished
t2 第8 computer finished
t1 第4 person
t2 第9 computer finished
t1 第5 person
t1 第6 person
t1 第7 person
t1 第8 person
t1 第9 person
可以看出,打印的结果是无序的,所以两种类型的锁互不影响。
static synchronized 和 方法代码块中synchronized (类名)都是对类 加锁。