所謂線程八鎖實(shí)際上對(duì)應(yīng)于是否加上synchronized,是否加上static等8種常見情況,代碼如下:
1.兩個(gè)普通同步方法,兩個(gè)線程,標(biāo)準(zhǔn)打印,結(jié)果:one two
public class TestThread8Monitor {
public static void main(String[] args) {
final Number number = new Number();
new Thread(new Runnable() {
@Override
public void run() {
number.getOne();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
number.getTwo();
}
}).start();
}
}
class Number{
public synchronized void getOne(){
System.out.println("one");
}
public synchronized void getTwo(){
System.out.println("Two");
}
}
2.新增Thread.sleep()給getOne(),結(jié)果:one two
public class TestThread8Monitor {
public static void main(String[] args) {
final Number number = new Number();
new Thread(new Runnable() {
@Override
public void run() {
number.getOne();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
number.getTwo();
}
}).start();
}
}
class Number{
public synchronized void getOne(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("one");
}
public synchronized void getTwo(){
System.out.println("Two");
}
}
3.新增普通方法getThree(),結(jié)果:three one two
public class TestThread8Monitor {
public static void main(String[] args) {
final Number number = new Number();
new Thread(new Runnable() {
@Override
public void run() {
number.getOne();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
number.getTwo();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
number.getThree();
}
}).start();
}
}
class Number{
public synchronized void getOne(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("one");
}
public synchronized void getTwo(){
System.out.println("Two");
}
public void getThree(){
System.out.println("Three");
}
}
4.兩個(gè)普通同步方法,兩個(gè)對(duì)象,結(jié)果:two one
public class TestThread8Monitor {
public static void main(String[] args) {
final Number number1 = new Number();
final Number number2 = new Number();
new Thread(new Runnable() {
@Override
public void run() {
number1.getOne();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
number2.getTwo();
}
}).start();
}
}
class Number{
public synchronized void getOne(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("one");
}
public synchronized void getTwo(){
System.out.println("Two");
}
}
5.修改getOne()為靜態(tài)同步方法,結(jié)果:two one
public class TestThread8Monitor {
public static void main(String[] args) {
final Number number1 = new Number();
final Number number2 = new Number();
new Thread(new Runnable() {
@Override
public void run() {
number1.getOne();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
number2.getTwo();
}
}).start();
}
}
class Number{
public static synchronized void getOne(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("one");
}
public synchronized void getTwo(){
System.out.println("Two");
}
}
6.修改兩個(gè)方法均為靜態(tài)同步方法,一個(gè)對(duì)象,結(jié)果:one two
public class TestThread8Monitor {
public static void main(String[] args) {
final Number number1 = new Number();
new Thread(new Runnable() {
@Override
public void run() {
number1.getOne();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
number1.getTwo();
}
}).start();
}
}
class Number{
public static synchronized void getOne(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("one");
}
public static synchronized void getTwo(){
System.out.println("Two");
}
}
7.一個(gè)靜態(tài)同步方法,一個(gè)非靜態(tài)同步方法,兩個(gè)對(duì)象,結(jié)果:two one
public class TestThread8Monitor {
public static void main(String[] args) {
final Number number1 = new Number();
final Number number2 = new Number();
new Thread(new Runnable() {
@Override
public void run() {
number1.getOne();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
number2.getTwo();
}
}).start();
}
}
class Number{
public static synchronized void getOne(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("one");
}
public synchronized void getTwo(){
System.out.println("Two");
}
}
8.兩個(gè)靜態(tài)同步方法,兩個(gè)對(duì)象,結(jié)果:one two
public class TestThread8Monitor {
public static void main(String[] args) {
final Number number1 = new Number();
final Number number2 = new Number();
new Thread(new Runnable() {
@Override
public void run() {
number1.getOne();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
number2.getTwo();
}
}).start();
}
}
class Number{
public static synchronized void getOne(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("one");
}
public static synchronized void getTwo(){
System.out.println("Two");
}
}
以上就是線程的八種常見的情況,線程八鎖的關(guān)鍵在于:
非靜態(tài)方法的鎖默認(rèn)為this,靜態(tài)方法的鎖為對(duì)應(yīng)的class實(shí)例(這里是Number.class)
某一個(gè)時(shí)刻內(nèi),只能有一個(gè)線程持有鎖,無論有幾個(gè)方法。
總結(jié):
①一個(gè)對(duì)象里面如果有多個(gè)synchronized方法,某一個(gè)時(shí)刻內(nèi),只要一個(gè)線程去調(diào)用其中的一個(gè)synchronized方法了,其他的線程都只能等待,換句話說,某一時(shí)刻內(nèi),只能有唯一一個(gè)線程去訪問這些synchronized方法。
②鎖的是當(dāng)前對(duì)象this,被鎖定后,其他線程都不能進(jìn)入到當(dāng)前對(duì)象的其他的synchronized方法。
③加個(gè)普通方法后發(fā)現(xiàn)和同步鎖無關(guān)。
④換成靜態(tài)同步方法后,情況又變化
⑤所有的非靜態(tài)同步方法用的都是同一把鎖 -- 實(shí)例對(duì)象本身,也就是說如果一個(gè)實(shí)例對(duì)象的非靜態(tài)同步方法獲取鎖后,該實(shí)例對(duì)象的其他非靜態(tài)同步方法必須等待獲取鎖的方法釋放鎖后才能獲取鎖,可是別的實(shí)例對(duì)象的非靜態(tài)同步方法因?yàn)楦搶?shí)例對(duì)象的非靜態(tài)同步方法用的是不同的鎖,所以毋須等待該實(shí)例對(duì)象已經(jīng)取鎖的非靜態(tài)同步方法釋放鎖就可以獲取他們自己的鎖。
⑥所有的靜態(tài)同步方法用的也是同一把鎖 -- 類對(duì)象本身,這兩把鎖是兩個(gè)不同的對(duì)象,所以靜態(tài)同步方法與非靜態(tài)同步方法之間不會(huì)有競(jìng)爭(zhēng)條件。但是一旦一個(gè)靜態(tài)同步方法獲取鎖后,其他的靜態(tài)同步方法都必須等待該方法釋放鎖后才能獲取鎖,而不管是同一個(gè)實(shí)例對(duì)象的靜態(tài)同步方法之間,還是不同的實(shí)例對(duì)象的靜態(tài)同步方法之間,只要它們是同一個(gè)實(shí)例對(duì)象