第一個示例更多的是運用了內部類的特性:
內部類重要特點:可以訪問外部的成員變量,所以內部類不能在靜態方法中實例化。
因為靜態方法運行時不需要創建實例對象,而內部類想要訪問成員變量,意味著外部類肯定要創建實例對象,二者相互矛盾。
所以下面就會報錯
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();
}
// 此方法被調用時一定創建了外部類對象
private void init() {
// 運行時找外部類對象,找調用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()然后調用outputer(name)仍然會出錯,因為每次new都是產生一個新的對象,而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() { // 要執行的操作
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");
//這樣仍然會出問題 ----不是同一個對象。
// 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();
// }
// }
//
// }
}
一個內部類前面加上static就變成了外部類
靜態方法只能在外部類中聲明
靜態方法只和字節碼對象有關
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() { // 要執行的操作
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.outputer2("lisi");
}
}
}).start();
}
static class Outputer { // 加上static 相當于是個外部類
public void outputer(String name) {
int len = name.length();
// 靜態方法不創建類的實例對象,創建字節碼對象,靜態方法運行時只和字節碼對象關聯
synchronized (Outputer.class) {
for (int i = 0; i < len; i++) {
System.out.print(name.charAt(i));
}
System.out.println();
}
}
// synchronized要在void之前
// 靜態方法只能在外部類中聲明
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();
}
}
}