java中同步synchronized的意義,如何用它解決線程不安全的問題
馬克-to-win:從上節(jié)我們學(xué)到,當(dāng)多個線程訪問且更改同一個變量時,很容易出現(xiàn)線程安全問題,誠然,我們可以通過一些其他手段,比如局部變量,多個實例,調(diào)整程序結(jié)構(gòu)來解決線程安全問題,但是通常來講,通過同步機(jī)制 synchronized來解決線程安全問題更加確定。比如,由于需求等其他限制條件決定,我們不能夠用局部變量或多個實例或什么其他辦法解決怎么辦? synchronized為我們提供了比較確定的方法。換句話說,線程安全問題, synchronized基本能解決。分析上一節(jié)的線程安全問題,我們發(fā)現(xiàn)問題的起因主要是兩個線程同時訪問更改共同的變量造成的,只要我們讓能夠更改共同變量的方法序列的執(zhí)行,(換句話就是一個執(zhí)行完后,另一個再執(zhí)行,) 就沒問題了。如何實現(xiàn)呢? 用synchronized,現(xiàn)在針對上一節(jié)有問題的例子:1.8.1_b,我們只加一個字synchronized, 問題就解決了,馬克- to-win:馬克 java社區(qū):防盜版實名手機(jī)尾號: 73203。
例1.9.1-本章源碼
class Photoshop {
private Photoshop() {
}
private static Photoshop photoshop = null;
public synchronized static Photoshop getInstanceQixy() {
if (photoshop == null) {
photoshop = new Photoshop();
}
return photoshop;
}
}
class MyThreadMark_to_win extends Thread {
public void run() {
Photoshop photoshopI1 = Photoshop.getInstanceQixy();
System.out.println(Thread.currentThread().getName() + "實例是 "
+ photoshopI1);
}
}
public class Test {
public static void main(String[] args) {
MyThreadMark_to_win mt1 = new MyThreadMark_to_win();
MyThreadMark_to_win mt2 = new MyThreadMark_to_win();
mt1.start();
mt2.start();
}
}
輸出結(jié)果:
Thread-1實例是 Photoshop@a62fc3
Thread-0實例是 Photoshop@a62fc3
現(xiàn)在針對上一節(jié)有問題的例子:1.8.2_b,我們只加一個字synchronized, 問題也能解決,我們看一下。
例1.9.2-本章源碼
class BookMark_to_win {
int bookNum=10;
synchronized void onlySellOne() {
if (bookNum > 0) {
System.out.println(Thread.currentThread().getName()
+ " before" + bookNum);
bookNum--;
try {
Thread.sleep(1000);
} catch (Exception e) {
}
System.out.println(Thread.currentThread().getName()
+ " after " + bookNum);
}
}
}
class MyThread extends Thread {
BookMark_to_win book;
MyThread(BookMark_to_win tmp) {
this.book = tmp;
}
public void run() {
/*run()里不能就只是寫book.onlySellOne(), 因為會呈現(xiàn)
兩個線程在那交替的效果*/
while (book.bookNum>0) {
book.onlySellOne();
}
}
}
public class Test {
public static void main(String[] args) {
BookMark_to_win bookM = new BookMark_to_win();
Thread t1 = new MyThread(bookM);
Thread t2 = new MyThread(bookM);
t1.start();
t2.start();
}
}
輸出結(jié)果:
Thread-0 before10
Thread-0 after 9
Thread-0 before9
Thread-0 after 8
Thread-0 before8
Thread-0 after 7
Thread-0 before7
Thread-0 after 6
Thread-1 before6
Thread-1 after 5
Thread-1 before5
Thread-1 after 4
Thread-0 before4
Thread-0 after 3
Thread-0 before3
Thread-0 after 2
Thread-0 before2
Thread-0 after 1
Thread-0 before1
Thread-0 after 0
if (bookNum > 0) {直接執(zhí)行完了,就可以退出synchronized塊兒了,要想不切換,就if變成while,就一個線程知道執(zhí)行完為止。),完美配合,從10到0,一個一個的遞減。perfect!