在開發當中使用多線程的,經常會用到synchronized和volatitle。接下來就講講他們的使用場景。
synchronized
java關鍵字,方法用到這個關鍵字則對這個方法進行加鎖。一次只能進入一個線程,其他線程只能等待或執行其他沒有加鎖的方法。等到這個線程完成後,下個線程才能進去。這樣保證數據的原子性,同時性能也就下降。
volatile
java關鍵字,用來聲明變量。
1.可見性
保證所有的線程的可見性,當一個線程修改了這個變量的值,volatile 保證了新值能立即同步到主內存,這樣其他線程獲取的是最新的值,保證了這個變量共享。
2.禁止指令重排序
指定重排序會涉及到編譯器和處理器,單線程再跑程序的時候處理器會按照編譯器的順序執行,當多個線程在跑的時候,處理器就不按照編譯器的順序來,自己會重排序。(什麼是指令重排序:是指CPU採用了允許將多條指令不按程序規定的順序分開發送給各相應電路單元處理)
3.原子性
volatile不保證原子性,會存在線程安全問題。
synchronized例子:
package com.company;
public class Main extends Thread {
//剩餘票數
private int ticket = 1000;
//購買票數
private int buy = 0;
@Override
public void run() {
long startTime = System.currentTimeMillis();
while (ticket > 0) {
synchronized (this) {
if (ticket > 0) {
ticket--;
buy++;
System.out.println("線程名" + Thread.currentThread().getName() + "餘票:" + ticket + "," + "出售:" + buy);
}
}
}
System.out.println("消耗:" + (System.currentTimeMillis() - startTime) + "ms");
}
public static void main(String[] args) {
System.out.println("主線程:" + Thread.currentThread().getName());
Main main = new Main();
new Thread(main).start();
new Thread(main).start();
new Thread(main).start();
new Thread(main).start();
new Thread(main).start();
}
}
volatile例子:
package com.company;
public class Main extends Thread {
//剩餘票數
private volatile int ticket = 1000;
//購買票數
private int buy = 0;
@Override
public void run() {
long startTime = System.currentTimeMillis();
while (ticket > 0) {
// synchronized (this) {
if (ticket > 0) {
ticket--;
buy++;
System.out.println("線程名" + Thread.currentThread().getName() + "餘票:" + ticket + "," + "出售:" + buy);
}
// }
}
System.out.println("消耗:" + (System.currentTimeMillis() - startTime) + "ms");
}
public static void main(String[] args) {
System.out.println("主線程:" + Thread.currentThread().getName());
Main main = new Main();
new Thread(main).start();
new Thread(main).start();
new Thread(main).start();
new Thread(main).start();
new Thread(main).start();
}
}