第一個示例更多的是運用了內(nèi)部類的特性:
內(nèi)部類重要特點:可以訪問外部的成員變量,所以內(nèi)部類不能在靜態(tài)方法中實例化。
因為靜態(tài)方法運行時不需要創(chuàng)建實例對象,而內(nèi)部類想要訪問成員變量,意味著外部類肯定要創(chuàng)建實例對象,二者相互矛盾。
所以下面就會報錯
public class Synchronized01 {
public static void main(String args[]) {
)
// final Outputer outputer=new Outputer(); //這樣做就沒有成員變量可以訪問
// new Thread(new Runnable(){
//
// public void run() {
// while(true){
// try {
// Thread.sleep(10);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// outputer.outputer("zhangsan");
// }
// }}).start();
}
class Outputer {
void outputer(String name) {
int len = name.length();
for (int i = 0; i < len; i++) {
System.out.print(name.charAt(i));
}
System.out.println();
}
}
}
但如果改成這樣就沒有問題
public class Synchronized01 {
public static void main(String args[]) {
new Synchronized01().init();
}
// 此方法被調(diào)用時一定創(chuàng)建了外部類對象
private void init() {
// 運行時找外部類對象,找調(diào)用init方法的對象
final Outputer outputer = new Outputer();
new Thread(new Runnable() {
public void run() {
while (true) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
outputer.outputer("zhangsan");
}
}
}).start();
new Thread(new Runnable() {
public void run() {
while (true) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
outputer.outputer("lisi");
}
}
}).start();
}
class Outputer {
void outputer(String name) {
int len = name.length();
for (int i = 0; i < len; i++) {
System.out.print(name.charAt(i));
}
System.out.println();
}
}
}
運行結果
lisi zhangsan lisi zhangsan lisi zhangsan lisi zhangsan lisi zhangsan
lisi zhangsan lisi zhangsan lisi zhanlgissain
zlhiasnig san lzihsain gsan zlhiasnig san zlhiasnig san zlhiasnig san
zlhiasnigsan zlhiasnig san lzihsain gsan lisi zhangsan lisi
解決方法
修改Ouputer
class Outputer {
public void outputer(String name) {
int len = name.length();
synchronized (this) {// 兩個線程用的是同一個outputer對象
for (int i = 0; i < len; i++) {
System.out.print(name.charAt(i));
}
System.out.println();
}
}
// synchronized要在void之前
// 一個方法只能有一個synchronized,不然可能會造成死鎖
public synchronized void outputer2(String name) {
int len = name.length();
for (int i = 0; i < len; i++) {
System.out.print(name.charAt(i));
}
System.out.println();
}
}
// class Outputer {
// String xxx = "";
//
// public void outputer(String name) {
// int len = name.length();
// xxx必須是同一個對象,如果是name就仍然會出錯 name是兩個對象
// synchronized (xxx) {
// for (int i = 0; i < len; i++) {
// System.out.print(name.charAt(i));
// }
// System.out.println();
// }
// }
//
// }
但如果每個run()中這樣寫new Outputer()然后調(diào)用outputer(name)仍然會出錯,因為每次new都是產(chǎn)生一個新的對象,而synchronized關鍵是針對同一個對象。
public class Synchronized02 {
public static void main(String[] args) {
new Synchronized02().init();
}
private void init() {
final Outputer outputer = new Outputer();
new Thread(new Runnable() {
public void run() { // 要執(zhí)行的操作
while (true) { // 循環(huán)操作
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
outputer.outputer("zhangsan");
}
}
}).start();
new Thread(new Runnable() {
public void run() {
while (true) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
outputer.outputer("lisi");
//這樣仍然會出問題 ----不是同一個對象。
// new Outputer().outputer("lisi"); }
}
}).start();
}
class Outputer {
public void outputer(String name) {
int len = name.length();
synchronized (this) {// 兩個線程用的是同一個outputer對象
for (int i = 0; i < len; i++) {
System.out.print(name.charAt(i));
}
System.out.println();
}
}
// synchronized要在void之前
// 一個方法只能有一個synchronized,不然可能會造成死鎖
public synchronized void outputer2(String name) {
int len = name.length();
for (int i = 0; i < len; i++) {
System.out.print(name.charAt(i));
}
System.out.println();
}
}
// class Outputer {
// String xxx = "";
//
// public void outputer(String name) {
// int len = name.length();
// xxx必須是同一個對象,如果是name就仍然會出錯 name是兩個對象
// synchronized (xxx) {
// for (int i = 0; i < len; i++) {
// System.out.print(name.charAt(i));
// }
// System.out.println();
// }
// }
//
// }
}
一個內(nèi)部類前面加上static就變成了外部類
靜態(tài)方法只能在外部類中聲明
靜態(tài)方法只和字節(jié)碼對象有關
public class Synchronized03 {
public static void main(String[] args) {
new Synchronized03().init();
}
private void init() {
final Outputer outputer = new Outputer();
new Thread(new Runnable() {
public void run() { // 要執(zhí)行的操作
while (true) { // 循環(huán)操作
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
outputer.outputer("zhangsan");
}
}
}).start();
new Thread(new Runnable() {
public void run() {
while (true) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
outputer.outputer2("lisi");
}
}
}).start();
}
static class Outputer { // 加上static 相當于是個外部類
public void outputer(String name) {
int len = name.length();
// 靜態(tài)方法不創(chuàng)建類的實例對象,創(chuàng)建字節(jié)碼對象,靜態(tài)方法運行時只和字節(jié)碼對象關聯(lián)
synchronized (Outputer.class) {
for (int i = 0; i < len; i++) {
System.out.print(name.charAt(i));
}
System.out.println();
}
}
// synchronized要在void之前
// 靜態(tài)方法只能在外部類中聲明
public static synchronized void outputer2(String name) {
int len = name.length();
for (int i = 0; i < len; i++) {
System.out.print(name.charAt(i));
}
System.out.println();
}
}
}