Java中,每个对象有且只有一个同步锁。调用对象的synchronized方法时,就获取了该对象的同步锁。
Java中一共有两种类型的锁
Java类锁(全局锁):类锁是用synchronized修饰类的静态方法或者一个类的class对象(一个类只有一个.class对象)
Java对象锁(实例锁):对象锁用synchronize修饰普通方法或者代码块
不同线程对锁的访问是互斥的。
synchronized的基本规则:
规则一. 当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程对“该对象”的该“synchronized方法”或者“synchronized代码块”的访问将被阻塞。
示例:
public class MyRunnable implements Runnable{
@Override
public void run() {
//获取当前对象的同步锁
synchronized (this){
try{
for(int i =0; i<5; i++){
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + " loop " + i);
}
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Runnable demo = new MyRunnable();
Thread thread1 = new Thread(demo,"thread1");
Thread thread2 = new Thread(demo,"thread2");
thread2.start();
thread1.start();
}
}
运行结果:
thread2 loop 0
thread2 loop 1
thread2 loop 2
thread2 loop 3
thread2 loop 4
thread1 loop 0
thread1 loop 1
thread1 loop 2
thread1 loop 3
thread1 loop 4
结果说明:
thread1和thread2都是基于"demo这个Runnable对象"创建的线程。这就意味着,我们可以将synchronized(this)中的this看作是“demo这个Runnable对象”;因此,线程t1和t2共享“demo对象的同步锁”。
另一个例子:
public class MyThread extends Thread {
public MyThread(String name){
super(name);
}
@Override
public void run() {
//获取当前对象的同步锁
synchronized (this){
for(int i =0; i<5; i++){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " loop " + i);
}
}
}
public static void main(String[] args) {
Thread thread1 = new MyThread("thread1");
Thread thread2 = new MyThread("thread2");
thread2.start();
thread1.start();
}
}
运行结果:
thread2 loop 0
thread1 loop 0
thread1 loop 1
thread2 loop 1
thread1 loop 2
thread2 loop 2
thread2 loop 3
thread1 loop 3
thread2 loop 4
thread1 loop 4
结果说明:
synchronized(this)中的this代表的是MyThread对象,而t1和t2是两个不同的MyThread对象,因此t1和t2在执行synchronized(this)时,获取的是不同对象的同步锁。
规则二. 当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程仍然可以访问“该对象”的非同步代码块。
public class Count {
public void synMethod(){
synchronized(this) {
try {
for (int i = 0; i < 5; i++) {
Thread.sleep(100); // 休眠100ms
System.out.println(Thread.currentThread().getName() + " synMethod loop " + i);
}
} catch (InterruptedException ie) {
}
}
}
public void nonSynMethod(){
try {
for (int i = 0; i < 5; i++) {
Thread.sleep(100); // 休眠100ms
System.out.println(Thread.currentThread().getName() + " nonSynMethod loop " + i);
}
} catch (InterruptedException ie) {
}
}
public static void main(String[] args) {
final Count count = new Count();
Thread t1 = new Thread(new Runnable() {
public void run() {
count.synMethod();
}
}, "t1");
Thread t2 = new Thread(new Runnable() {
public void run() {
count.nonSynMethod();
count.synMethod();
}
}, "t2");
t1.start();
t2.start();
}
}
运行结果:
t2 nonSynMethod loop 0
t1 synMethod loop 0
t1 synMethod loop 1
t2 nonSynMethod loop 1
t2 nonSynMethod loop 2
t1 synMethod loop 2
t2 nonSynMethod loop 3
t1 synMethod loop 3
t2 nonSynMethod loop 4
t1 synMethod loop 4
t2 synMethod loop 0
t2 synMethod loop 1
t2 synMethod loop 2
t2 synMethod loop 3
t2 synMethod loop 4
结果说明:t1,t2均访问的count对象,t1先获取到count对象的实例锁,t2先访问count的非同步代码块。等t1释放锁后,t2访问count对象的同步代码块。
规则三. 当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程对“该对象”的其他的“synchronized方法”或者“synchronized代码块”的访问将被阻塞。
示例:
public class Count {
//含有synchronized同步块的方法
public void synMethod1(){
synchronized (this){
try {
for (int i = 0; i < 5; i++) {
Thread.sleep(110); // 休眠110ms
System.out.println(Thread.currentThread().getName() + " synMethod1 loop " + i);
}
} catch (InterruptedException ie) {
}
}
}
//含有synchronized同步块的方法
public void synMethod2(){
synchronized (this){
try {
for (int i = 0; i < 6; i++) {
Thread.sleep(110); // 休眠110ms
System.out.println(Thread.currentThread().getName() + " synMethod2 loop " + i);
}
} catch (InterruptedException ie) {
}
}
}
//非同步的方法
public void nonsynMethod(){
try {
for (int i = 0; i < 6; i++) {
Thread.sleep(100); // 休眠100ms
System.out.println(Thread.currentThread().getName() + " nonsynMethod loop " + i);
}
} catch (InterruptedException ie) {
}
}
public static void main(String[] args) {
final Count count = new Count();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
count.synMethod1();
}
},"thread1");
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
count.nonsynMethod();
}
},"thread2");
Thread thread3 = new Thread(new Runnable() {
@Override
public void run() {
count.synMethod2();
}
},"thread3");
thread1.start();
thread2.start();
thread3.start();
}
}
运行结果:
thread2 nonsynMethod loop 0
thread1 synMethod1 loop 0
thread2 nonsynMethod loop 1
thread1 synMethod1 loop 1
thread2 nonsynMethod loop 2
thread1 synMethod1 loop 2
thread2 nonsynMethod loop 3
thread1 synMethod1 loop 3
thread1 nonsynMethod loop 4
thread1 synMethod1 loop 4
thread2 nonsynMethod loop 5
thread3 synMethod2 loop 0
thread1 synMethod2 loop 1
thread3 synMethod2 loop 2
thread3 synMethod2 loop 3
thread3 synMethod2 loop 4
thread3 synMethod2 loop 5
结果说明:
thread1,thread1,thread3都是基于同一个count对象创建的线程。
关于全局锁和实例锁的一些说明:
pulbic class Something {
public synchronized void isSyncA(){}
public synchronized void isSyncB(){}
public static synchronized void cSyncA(){}
public static synchronized void cSyncB(){}
}
(01) x.isSyncA()与x.isSyncB()
(02) x.isSyncA()与y.isSyncA()
(03) x.cSyncA()与y.cSyncB()
(04) x.isSyncA()与Something.cSyncA()
(01) 不能被同时访问。因为isSyncA()和isSyncB()都是访问同一个对象(对象x)的同步锁!
public class LockDemo {
public synchronized void isSyncA() {
try {
for (int i=0;i<5;i++) {
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + " : isSyncA");
}
} catch (InterruptedException ie) {
}
}
public synchronized void isSyncB(){
try {
for (int i=0;i<5;i++) {
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + " : isSyncB");
}
} catch (InterruptedException ie) {
}
}
public static void main(String[] args) {
final LockDemo lockDemo1 = new LockDemo();
final LockDemo lockDemo2 = new LockDemo();
Thread t11 = new Thread(new Runnable() {
@Override
public void run() {
lockDemo1.isSyncA();
}
},"t11");
Thread t12 = new Thread(new Runnable() {
@Override
public void run() {
lockDemo1.isSyncB();
}
},"t12");
t11.start();
t12.start();
}
}
运行结果:
t11 : isSyncA
t11 : isSyncA
t11 : isSyncA
t11 : isSyncA
t11 : isSyncA
t12 : isSyncB
t12 : isSyncB
t12 : isSyncB
t12 : isSyncB
t12 : isSyncB
结果说明:访问的均是lockDemo1对象的同步锁。
(02) 可以同时被访问
public class LockDemo {
public synchronized void isSyncA() {
try {
for (int i=0;i<5;i++) {
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + " : isSyncA");
}
} catch (InterruptedException ie) {
}
}
public synchronized void isSyncB(){
try {
for (int i=0;i<5;i++) {
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + " : isSyncB");
}
} catch (InterruptedException ie) {
}
}
public static void main(String[] args) {
final LockDemo lockDemo1 = new LockDemo();
final LockDemo lockDemo2 = new LockDemo();
Thread t11 = new Thread(new Runnable() {
@Override
public void run() {
lockDemo1.isSyncA();
}
},"t11");
Thread t12 = new Thread(new Runnable() {
@Override
public void run() {
lockDemo2.isSyncB();
}
},"t12");
t11.start();
t12.start();
}
}
运行结果:
t12 : isSyncB
t11 : isSyncA
t12 : isSyncB
t11 : isSyncA
t12 : isSyncB
t11 : isSyncA
t12 : isSyncB
t11 : isSyncA
t12 : isSyncB
t11 : isSyncA
结果说明:访问的是lockDemo1与lockDemo2两个对象的同步锁。
(03) 不能被同时访问。
public class LockDemo {
public synchronized void isSyncA() {
try {
for (int i=0;i<5;i++) {
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + " : isSyncA");
}
} catch (InterruptedException ie) {
}
}
public synchronized void isSyncB(){
try {
for (int i=0;i<5;i++) {
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + " : isSyncB");
}
} catch (InterruptedException ie) {
}
}
public static synchronized void cSyncA(){
try{
for (int i=0;i<5;i++) {
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + " : csyncA");
}
} catch (InterruptedException ie) {
}
}
public static synchronized void cSyncB(){
try{
for (int i=0;i<5;i++) {
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + " : csyncB");
}
} catch (InterruptedException ie) {
}
}
public static void main(String[] args) {
final LockDemo lockDemo1 = new LockDemo();
final LockDemo lockDemo2 = new LockDemo();
Thread t11 = new Thread(new Runnable() {
@Override
public void run() {
lockDemo1.isSyncA();
}
},"t11");
Thread t12 = new Thread(new Runnable() {
@Override
public void run() {
lockDemo2.isSyncB();
}
},"t12");
Thread t13 = new Thread(new Runnable() {
@Override
public void run() {
LockDemo.cSyncA();
}
},"t13");
Thread t14 = new Thread(new Runnable() {
@Override
public void run() {
LockDemo.cSyncB();
}
},"t14");
// t11.start();
// t12.start();
t13.start();
t14.start();
}
}
运行结果:
t13 : csyncA
t13 : csyncA
t13 : csyncA
t13 : csyncA
t13 : csyncA
t14 : csyncB
t14 : csyncB
t14 : csyncB
t14 : csyncB
t14 : csyncB
结果说明:访问的都是LockDemo的同步锁
(04) 可以被同时访问。
运行结果:
t13 : csyncA
t12 : isSyncB
t12 : isSyncB
t13 : csyncA
t13 : csyncA
t12 : isSyncB
t13 : csyncA
t12 : isSyncB
t13 : csyncA
t12 : isSyncB
结果说明:因为isSyncA()是实例方法,x.isSyncA()使用的是对象x的锁;而cSyncA()是静态方法,Something.cSyncA()可以理解对使用的是“类的锁”。因此,它们是可以被同时访问的。
网友评论