Java中床估,每個對象有且只有一個同步鎖。調(diào)用對象的synchronized方法時,就獲取了該對象的同步鎖蛋欣。
Java中一共有兩種類型的鎖
Java類鎖(全局鎖):類鎖是用synchronized修飾類的靜態(tài)方法或者一個類的class對象(一個類只有一個.class對象)
Java對象鎖(實例鎖):對象鎖用synchronize修飾普通方法或者代碼塊
不同線程對鎖的訪問是互斥的。
synchronized的基本規(guī)則:
規(guī)則一. 當一個線程訪問“某對象”的“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();
}
}
運行結(jié)果:
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
結(jié)果說明:
thread1和thread2都是基于"demo這個Runnable對象"創(chuàng)建的線程。這就意味著杠袱,我們可以將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();
}
}
運行結(jié)果:
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
結(jié)果說明:
synchronized(this)中的this代表的是MyThread對象凿掂,而t1和t2是兩個不同的MyThread對象,因此t1和t2在執(zhí)行synchronized(this)時纹蝴,獲取的是不同對象的同步鎖庄萎。
規(guī)則二. 當一個線程訪問“某對象”的“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();
}
}
運行結(jié)果:
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
結(jié)果說明:t1糠涛,t2均訪問的count對象秉馏,t1先獲取到count對象的實例鎖,t2先訪問count的非同步代碼塊脱羡。等t1釋放鎖后萝究,t2訪問count對象的同步代碼塊。
規(guī)則三. 當一個線程訪問“某對象”的“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();
}
}
運行結(jié)果:
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
結(jié)果說明:
thread1,thread1脓规,thread3都是基于同一個count對象創(chuàng)建的線程栽连。
關(guān)于全局鎖和實例鎖的一些說明:
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();
}
}
運行結(jié)果:
t11 : isSyncA
t11 : isSyncA
t11 : isSyncA
t11 : isSyncA
t11 : isSyncA
t12 : isSyncB
t12 : isSyncB
t12 : isSyncB
t12 : isSyncB
t12 : isSyncB
結(jié)果說明:訪問的均是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();
}
}
運行結(jié)果:
t12 : isSyncB
t11 : isSyncA
t12 : isSyncB
t11 : isSyncA
t12 : isSyncB
t11 : isSyncA
t12 : isSyncB
t11 : isSyncA
t12 : isSyncB
t11 : isSyncA
結(jié)果說明:訪問的是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();
}
}
運行結(jié)果:
t13 : csyncA
t13 : csyncA
t13 : csyncA
t13 : csyncA
t13 : csyncA
t14 : csyncB
t14 : csyncB
t14 : csyncB
t14 : csyncB
t14 : csyncB
結(jié)果說明:訪問的都是LockDemo的同步鎖
(04) 可以被同時訪問熔恢。
運行結(jié)果:
t13 : csyncA
t12 : isSyncB
t12 : isSyncB
t13 : csyncA
t13 : csyncA
t12 : isSyncB
t13 : csyncA
t12 : isSyncB
t13 : csyncA
t12 : isSyncB
結(jié)果說明:因為isSyncA()是實例方法,x.isSyncA()使用的是對象x的鎖臭笆;而cSyncA()是靜態(tài)方法叙淌,Something.cSyncA()可以理解對使用的是“類的鎖”。因此愁铺,它們是可以被同時訪問的鹰霍。