/**
* @Author xty
* @Description
* @Date 19:31 2018/11/12
*/
public class Counter {
private int count;
public void add(){
try{
for (int i = 0;i<200;i++){
Thread.sleep(100);
this.count++;
System.out.println(this.count);
}
}catch (Exception e ){
e.printStackTrace();
}
}
}
/**
* @Author xty
* @Description
* @Date 19:33 2018/11/12
*/
public class Test {
public static void main(String[] args) {
final Counter counter = new Counter();
new Thread(new Runnable() {
@Override
public void run() {
counter.add();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
counter.add();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
counter.add();
}
}).start();
}
}
新建兩個類,運行之後總數並沒有到3*200 ,因爲產生了併發問題。
解決方法1.
/**
* @Author xty
* @Description
* @Date 19:31 2018/11/12
*/
public class Counter {
private int count;
public synchronized void add(){
try{
for (int i = 0;i<200;i++){
Thread.sleep(100);
this.count++;
System.out.println(this.count);
}
}catch (Exception e ){
e.printStackTrace();
}
}
}
雖然結果對了,但是使用了synchronized 效率極其低下。
解決方法2.
/**
* @Author xty
* @Description
* @Date 19:31 2018/11/12
*/
public class Counter {
private int count;
public void add(){
try{
for (int i = 0;i<200;i++){
Thread.sleep(100);
synchronized(this) {
this.count++; //競爭條件
System.out.println(this.count);
}
}
}catch (Exception e ){
e.printStackTrace();
}
}
}
將synchronized加入到關鍵部位(競爭條件),效率有所提升。
解決方法3.
/**
* @Author xty
* @Description
* @Date 19:31 2018/11/12
*/
public class Counter {
//原子性
private AtomicInteger count = new AtomicInteger();
public void add(){
try{
for (int i = 0;i<200;i++){
Thread.sleep(100);
count.incrementAndGet();
System.out.println(this.count);
}
}catch (Exception e ){
e.printStackTrace();
}
}
}
使用AtomicInteger 類。輸出順序並沒有保證,但是最後的結果是正確的。因爲排隊效率會低。
可重入鎖:
一個線程獲取它本生已經持有的鎖,這是可以成功的。我們知道多個線程同時搶佔同一個鎖它們是失敗的。因爲它們之間是互斥的。但是呢,一個線程再次獲取一個自己已經拿過的鎖是可以成功的,那麼它是能夠成功的。
public class Widget {
public synchronized void doSth(){
}
}
public class ChildWidget extends Widget {
@Override
public synchronized void doSth() {
super.doSth();
}
}
public class Test {
public static void main(String[] args) {
Widget w = new ChildWidget();
w.doSth();
}
}
子類和父類調用的鎖都是w這個對象,因此這種方式叫做內部鎖的可重入機制,也叫可重入鎖。