一道面试题引发的思考--Java锁的思考

876 阅读2分钟

使用3个线程,1个线程打印X,一个线程打印Y,一个线程打印Z,同时执行连续打印10次"XYZ"

问题分析:核心是同一时间只有一个任务在执行,当前任务执行后把执行权交给特定的线程。我们把执行权抽象为资源。那么模型可以抽象为线程如果想要执行必须检查自己执行所需的的资源是不是满足,如果满足则去执行而且在持有资源期间资源不会被其他线程获取。首先我们想到锁是具有互持性的,我们可以通过这一特性去实现,接下来我们分别使用synchronized+notify方式Lock+Condition的方式和CAS的操作来实现

Lock+Condition condition

public class Test1 {
public static void main(String[] args) {
    Lock lock = new ReentrantLock();
    Condition conditionX = lock.newCondition();
    Condition conditionY = lock.newCondition();
    Condition conditionZ = lock.newCondition();
    int time = 10;
    Thread x = new Thread(new Task("X", time, lock, conditionX, conditionY));
    Thread y = new Thread(new Task("Y", time, lock, conditionY, conditionZ));
    Thread z = new Thread(new Task("Z", time, lock, conditionZ, conditionX));
    x.start();
    y.start();
    z.start();
}

static class Task implements Runnable {
    /**
     * 实际执行任务内容
     */
    private String name;
    /**
     * 任务执行次数
     */
    private int time;
    /**
     *同步锁
     */
    private Lock lock;
    /**
     * 等待资源
     */
    private Condition wait;
    /**
     * 唤醒资源
     */
    private Condition notify;

    public Task(String name, int time, Lock lock, Condition wait, Condition notify) {
        this.name = name;
        this.time = time;
        this.lock = lock;
        this.wait = wait;
        this.notify = notify;
    }

    @Override
    public void run() {
        int count = 0;
        while (count < time) {
            count++;
            lock.lock();
            System.out.println(name);
            try {
                notify.signal();
                wait.await();
            } catch (InterruptedException ignore) {

            }
        }

    }
}

}

synchronized+notify方式

public class Sync {
private static int next = 0;

public static void main(String[] args) {
    Object lock = new Object();
    new Thread(new Task(0, lock, "X")).start();
    new Thread(new Task(1, lock, "Y")).start();
    new Thread(new Task(2, lock, "Z")).start();

}

static class Task implements Runnable {
    private int t;
    private Object lock;
    private String name;

    public Task(int t, Object lock, String name) {
        this.t = t;
        this.lock = lock;
        this.name = name;
    }

    @Override
    public void run() {
        while (next < 30) {
            synchronized (lock) {
                if (next % 3 == t) {
                    System.out.println(name);
                    next++;
                }
                try {
                    lock.notifyAll();
                    lock.wait();
                } catch (Exception ignore) {

                }
            }

        }

    }
}

}

CAS方式

public class Test1NoLock {
 private static final int run=3;

public static void main(String[] args) throws InterruptedException {

    AtomicInteger integer=new AtomicInteger(0);
    new Thread(new Task("X",10,0,1,integer)).start();
    new Thread(new Task("Y",10,1,2,integer)).start();
    new Thread(new Task("Z",10,2,0,integer)).start();

}

static class Task implements  Runnable{
    private String name;
    private int time;
    private int expect;
    private  int update;
    private AtomicInteger integer;

    public Task(String name, int time,int expect, int update, AtomicInteger integer) {
        this.name = name;
        this.time=time;
        this.expect = expect;
        this.update = update;
        this.integer = integer;
    }

    @Override
    public void run() {
        int count=0;
        while (count<time) {
            if (integer.compareAndSet(expect,run)){
                count++;
                System.out.println(name);
                integer.compareAndSet(3,update);
            }
        }

    }
}

}