直接看代碼:
背景:模仿多線程搶票
package com.example.institution01.instiServic;
import java.util.ArrayList;
import java.util.List;
public class ThreadTest {
/**總票數**/
static int a = 1;
public static void method() {
/**搶票t1**/
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
String sell = sell();
System.out.println(sell);
}
});
/**搶票t2**/
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
String sell = sell();
System.out.println(sell);
}
});
t1.start();
t2.start();
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
method();
}
}
/**出票系統**/
public static String sell(){
a = a - 1;
if (a >= 0)
return Thread.currentThread().getName()+"搶到票===剩餘=" + a;
else
return Thread.currentThread().getName()+"無票";
}
}
控制檯結果:
Thread-0搶到票===剩餘=-1
Thread-4無票
Thread-2無票
Thread-3無票
Thread-1無票
Thread-6無票
Thread-5無票
Thread-7無票
Thread-8無票
Thread-10無票
Thread-11無票
Thread-9無票
Thread-14無票
Thread-15無票
Thread-13無票
Thread-12無票
Thread-17無票
Thread-16無票
Thread-18無票
Thread-19無票
可以看到有一個Thread-0搶到票===剩餘=-1的線程:
A線程:a=1 a-1 a=0;
B線程:a=0 a-1 a=-1;
B線程在A線程沒有結束的時候改變了a的值,所以A線程輸出剩餘-1張票;
1.加 synchronized 關鍵字後:
package com.example.institution01.instiServic;
import java.util.ArrayList;
import java.util.List;
public class ThreadTest {
/**總票數**/
static int a = 1;
public static void method() {
/**搶票t1**/
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
String sell = sell();
System.out.println(sell);
}
});
/**搶票t2**/
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
String sell = sell();
System.out.println(sell);
}
});
t1.start();
t2.start();
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
method();
}
}
/**出票系統**/
public synchronized static String sell(){
a = a - 1;
if (a >= 0)
return Thread.currentThread().getName()+"搶到票===剩餘=" + a;
else
return Thread.currentThread().getName()+"無票";
}
}
控制檯:
Thread-1無票
Thread-5無票
Thread-4無票
Thread-3無票
Thread-2無票
Thread-6無票
Thread-0搶到票===剩餘=0
Thread-7無票
Thread-10無票
Thread-9無票
Thread-11無票
Thread-8無票
Thread-12無票
Thread-13無票
Thread-15無票
Thread-14無票
Thread-17無票
Thread-16無票
Thread-18無票
Thread-19無票
完美解決這個問題!
2.用LOCK鎖解決:
package com.example.institution01.instiServic;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ThreadTest {
private static Lock lock = new ReentrantLock();
/**總票數**/
static int a = 1;
public static void method() {
/**搶票t1**/
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
lock.lock();
String sell = sell();
System.out.println(sell);
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
});
/**搶票t2**/
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
try {
lock.lock();
String sell = sell();
System.out.println(sell);
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
});
t1.start();
t2.start();
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
method();
}
}
/**出票系統**/
public static String sell(){
a = a - 1;
if (a >= 0)
return Thread.currentThread().getName()+"搶到票===剩餘=" + a;
else
return Thread.currentThread().getName()+"無票";
}
}
synchronized和Lock 的異同:
同:兩者都是解決線程安全問題
異:
- synchronized關鍵字定義的不管是同步代碼塊還是同步方法在執行完成之後都是自動的釋放同步監視器(這是一種隱式鎖,出了作用域隱式鎖將自動的釋放)
- lock需要手動的上鎖啓動同步和手動解鎖結束同步;
- Lock只有代碼塊鎖,沒辦法對某一方法上鎖
- Lock鎖比較靈活,JVM只需要花費較小的代價來實現線程的調度,性能更好並且有更好的擴展性;