Lock 和 synchronized的區別

項羽齊發表於2018-04-11

1、執行緒生命週期

執行緒總共有5大狀態

  • 新建狀態:新建執行緒物件,並沒有呼叫start()方法之前

  • 就緒狀態:呼叫start()方法之後執行緒就進入就緒狀態,但是並不是說只要呼叫start()方法執行緒就馬上變為當前執行緒,在變為當前執行緒之前都是為就緒狀態。值得一提的是,執行緒在睡眠和掛起中恢復的時候也會進入就緒狀態哦。

  • 執行狀態:執行緒被設定為當前執行緒,開始執行run()方法。就是執行緒進入執行狀態

  • 阻塞狀態:執行緒被暫停,比如說呼叫sleep()方法後執行緒就進入阻塞狀態

  • 死亡狀態:執行緒執行結束

  

鎖型別

 

  • lock():獲取鎖,如果鎖被暫用則一直等待

  • unlock():釋放鎖

  • tryLock(): 注意返回型別是boolean,如果獲取鎖的時候鎖被佔用就返回false,否則返回true

  • tryLock(long time, TimeUnit unit):比起tryLock()就是給了一個時間期限,保證等待引數時間

  • lockInterruptibly():用該鎖的獲得方式,如果執行緒在獲取鎖的階段進入了等待,那麼可以中斷此執行緒,先去做別的事

 

package cn.xiang.thread.lock;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * lock鎖學習demo
 * 總結:
 *         1、使用lock.lock()方法可以將物件鎖定。同時必須在finally將鎖釋放lock.unlock(),否則其他物件獲取不了該鎖。
 *         2、如果是執行緒內新定義的物件,那麼有無鎖都會非同步執行,並不同步。
 * @author 向寧
 *日期:2018年4月11日
 *時間:下午3:26:06
 *
 */
public class LockDemo01 {
    /**
     * 建立鎖
     */
    private Lock lock = new ReentrantLock();
    
    /**
     * 需要同步執行的方法
     * @param thread
     * @throws InterruptedException 
     */
    public void lockMethod(){
        System.out.println("還沒開始鎖定");
        lock.lock();
        Thread thread = Thread.currentThread();
        System.out.println("我是" + thread.getName() + "!正在使用鎖");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally{
            lock.unlock();
        }
        
    }
    
    public static void main(String[] args) {
        final LockDemo01 lockDemo = new LockDemo01();
        Thread t1 = new Thread(){
            @Override
            public void run(){
                lockDemo.lockMethod();
            }
        };
        Thread t2 = new Thread(){
            @Override
            public void run(){
                lockDemo.lockMethod();
            }
        };
        t1.start();
        t2.start();
    }
}
LockDemo01

結果如下:

  

 

package cn.xiang.thread.lock;
/**
 * lock.tryLock()
 *         可if判斷該程式碼是否被鎖定。如果被鎖定,則不執行。
 * lock.tryLock(time, unit)
 *         給一個等待時間,等待時間過後,如果鎖定被釋放,則可以直接進入。如果等待時間已過,還不釋放。則直接執行else
 * 
 */

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockDemo02 {
    private Lock lock = new ReentrantLock();
    /**
     * 需要同步的方法
     */
    public void lockMethod(){
        try {
            System.out.println("開始執行方法");
            if (lock.tryLock(1, TimeUnit.SECONDS)) {
                //如果當前已經被鎖定
                try {
                    System.out.println("我是執行緒:" + Thread.currentThread().getName() + "!我已經拿到了該鎖!");
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally{
                    lock.unlock();
                }
                
            }else{
                System.out.println("我是執行緒:" + Thread.currentThread().getName() + "!我沒有拿到該鎖,就不要了!");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    public static void main(String[] args) {
        final LockDemo02 lockDemo = new LockDemo02();
        Thread t1 = new Thread(){
            @Override
            public void run(){
                lockDemo.lockMethod();
            }
        };
        Thread t2 = new Thread(){
            @Override
            public void run(){
                lockDemo.lockMethod();
            }
        };
        Thread t3 = new Thread(){
            @Override
            public void run(){
                lockDemo.lockMethod();
            }
        };
        t1.start();
        t2.start();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        t3.start();
    }
}
LockDemo02

結果如下:

  

 

 

以下是一個簡單的死鎖

package cn.xiang.thread;

public class ThreadDeadLock03 {
    
    public static void main(String[] args) {
        LockDemo04 lock = new LockDemo04(false);
        new Thread(lock).start();
        new Thread(lock).start();
        
    }
}

class LockDemo04 implements Runnable{
    private boolean flag;
    private Object obj1 = new Object();
    private Object obj2 = new Object();
    public LockDemo04(boolean flag){
        this.flag = flag;
    }
    @Override
    public void run() {
        flag = !flag;
        try {
            if(flag){
                synchronized(obj1){
                    System.out.println("已經拿到obj1的物件鎖");
                    Thread.sleep(1000);
                    System.out.println("準備拿obj2的物件鎖");
                    synchronized(obj2){
                        System.out.println("已經拿到obj2的物件鎖,表示沒有發生死鎖");
                    }
                }
            }else{
                synchronized(obj2){
                    System.out.println("已經拿到obj2的物件鎖");
                    Thread.sleep(1000);
                    System.out.println("準備拿obj1的物件鎖");
                    synchronized(obj1){
                        System.out.println("已經拿到obj1的物件鎖,表示沒有發生死鎖!");
                    }
                }
            }
        } catch (Exception e) {
            // TODO: handle exception
        }
    }
}

 

效果:

  

 

相關文章