java ReentrantLock与synchronized

synchronized 对象锁

   当多个线程在更新共享状态时避免相互冲突,要保证数据的原子性与可见性,我们通常用synchronized上锁,,一个线程访问synchornied代码库或者方法时,其他线程都将暂时不能访问,知道上一个线程调用的这个synchronized执行完成,才能被另外线程调用,synchronized将自动释放锁,此后另外线程等待到这时才能执行

   例1:并发线程等待

   

package com.example;

import com.example.bean.User;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Random;

public class SynchronizedClass {

    private static List<User> userList = new ArrayList<>();

    public static void main(String[] args) throws Exception {
        new Thread(new Runnable() {
            @Override
            public void run() {
                long startTime= Calendar.getInstance().getTimeInMillis();
                System.out.println("------->开始执行:thread:" + Thread.currentThread().getId() + "   userSize:" + userList.size() + "  execute time:" + Long.toString(startTime));
                addUser();
                long endTime=Calendar.getInstance().getTimeInMillis();
                System.out.println("------->结束执行:thread:" + Thread.currentThread().getId() + "   userSize:" + userList.size() + "  execute time:" + endTime+"  take Time:"+(endTime-startTime));
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                long startTime= Calendar.getInstance().getTimeInMillis();
                System.out.println("------->开始执行:thread:" + Thread.currentThread().getId() + "   userSize:" + userList.size() + "  execute time:" + startTime);
                addUser();
                long endTime=Calendar.getInstance().getTimeInMillis();
                System.out.println("------->结束执行:thread:" + Thread.currentThread().getId() + "   userSize:" + userList.size() + "  execute time:" + endTime+"  take Time:"+(endTime-startTime));
            }
        }).start();
    }

    public synchronized static void addUser() {
        User user = new User("name:" + System.currentTimeMillis(), new Random().nextInt(100));
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        userList.add(user);
    }
}

运行结果:

------->开始执行:thread:13   userSize:0  execute time:1462329339337
------->开始执行:thread:12   userSize:0  execute time:1462329339337
------->结束执行:thread:13   userSize:1  execute time:1462329344348  take Time:5011
------->结束执行:thread:12   userSize:2  execute time:1462329349348  take Time:10011

   例二:当一个线程访问对象锁时或者同步方法 其他线程也能访问非同步方法或非同步代码块

package com.example;

import com.example.bean.User;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Random;

public class SynchronizedClass {

    public static class Test {
        public void addUser() {
            synchronized (this) {
                User user = new User("name:" + System.currentTimeMillis(), new Random().nextInt(100));
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                userList.add(user);
            }
        }

        public synchronized void addUser2() {
            User user = new User("name:" + System.currentTimeMillis(), new Random().nextInt(100));
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            userList.add(user);
        }

        public void sayHello() {
            System.out.println("------->execute time:" + Calendar.getInstance().getTimeInMillis());
        }
    }

    private static List<User> userList = new ArrayList<>();

    public static void main(String[] args) throws Exception {
       Test t=new Test();
        new Thread(new Runnable() {
            @Override
            public void run() {
                long startTime = Calendar.getInstance().getTimeInMillis();
                System.out.println("------->开始执行:thread:" + Thread.currentThread().getId() + "   userSize:" + userList.size() + "  execute time:" + Long.toString(startTime));
                t.addUser();
                long endTime = Calendar.getInstance().getTimeInMillis();
                System.out.println("------->结束执行:thread:" + Thread.currentThread().getId() + "   userSize:" + userList.size() + "  execute time:" + endTime + "  take Time:" + (endTime - startTime));
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                long startTime = Calendar.getInstance().getTimeInMillis();
                System.out.println("------->开始执行:thread:" + Thread.currentThread().getId() + "   userSize:" + userList.size() + "  execute time:" + startTime);
                t.addUser();
                long endTime = Calendar.getInstance().getTimeInMillis();
                System.out.println("------->结束执行:thread:" + Thread.currentThread().getId() + "   userSize:" + userList.size() + "  execute time:" + endTime + "  take Time:" + (endTime - startTime));
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
              t.sayHello();
            }
        }).start();
    }


}


运行结果:

------->开始执行:thread:13   userSize:0  execute time:1462330376305
------->开始执行:thread:12   userSize:0  execute time:1462330376305
------->execute time:1462330376305
------->结束执行:thread:13   userSize:1  execute time:1462330381315  take Time:5010
------->结束执行:thread:12   userSize:2  execute time:1462330386315  take Time:10010

在jdk1.5 之后 java还增加了一种锁机制 Lock

   lock的实现类ReentrantLock 比较常用

  ReentrantLock 提供多样化的同步,比如时间限制的同步,可以被interrupt的同步(synchronized的同步是不能interrupt的)等。在资源警政不激烈的情况下,性能稍微比synchronized差点点,反之胜之,据官方称(伴随jvm的提升和优化,差距逐步缩小);reentrantLock还能维持常态:

  注意lock 必须手动释放,不同于synchronized,通常在finally 代码块中(synchronized 出现异常时jvm会自动释放,而lock jvm不会来管理,所以要确保一定释放)

  模板:

Lock lock = new ReentrantLock();
        lock.lock();
        try {

        } finally {
            lock.unlock();
        }
ReentrantLock 构造方式分为公平锁和非公平锁;synchronized永远是公平的

 /**
     * Creates an instance of {@code ReentrantLock}.
     * This is equivalent to using {@code ReentrantLock(false)}.
     */
    public ReentrantLock() {
        sync = new NonfairSync();
    }

    /**
     * Creates an instance of {@code ReentrantLock} with the
     * given fairness policy.
     *
     * @param fair {@code true} if this lock should use a fair ordering policy
     */
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }
公平情况下:操作会排一个队列按顺序执行,来保证执行的顺序性,同时也会消耗更多的时间

不公平情况下,是无序允许插队的,,jvm会自动计算如何处理更快速度来调度插队,理论更快


ReentrantLock获取锁的4种方式:

1:void lock(); 如果获取了锁立即返回,如果别的线程持有锁,当前线程则一直处于休眠状态,直到获取锁;

2:boolean tryLock(); 如果获取了锁立即返回true,如果别的线程持有锁,立即返回false;

3: boolean tryLock(longtime, TimeUnit unit) throws InterruptedException;如果获取了锁立即返回true,如果别的线程持有锁,会等待参数给定的时间,在等待的过程中,如果获取了锁,立即返回true,如果等待超时,返回false;

4:void lockInterruptibly() throws InterruptedException;如果获取了锁立即返回,如果没有获取锁,当前线程处于休眠状态,直到当前线程中断



使用场景:防止重复触发:UI疯狂点击,清除无用的临时文件,数据库备份: 建议是用tryLock

                同步执行:防止共享资源的冲突,保证同一个时间段内只有一个操作可以使用该资源,如断点续传,使用lock(),当资源被其他线程锁定,会等待锁释放,继续执行

                已有任务执行,冗长一段时间后 是否可以继续执行 使用tryLock(time),超过这个时间依旧不可以获得锁立即返回false 使用注意事项,这个方法会抛出中断异常

               synchronized与lock在默认情况下是不会相应中断(interrupt)操作,会继续执行完成,lockInterruptibly提供可中断锁来解决此问题

   例3:   lock实例

package com.example;

import com.example.bean.User;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Random;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author xuanyouwu
 * @email [email protected]
 * @time 2016-05-04 11:09
 */
public class LockClass {
    public static class Test {
        Lock lock = new ReentrantLock();
        public void addUser() {
            try {
                lock.lock();
                User user = new User("name:" + System.currentTimeMillis(), new Random().nextInt(100));
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                }
                userList.add(user);
            } finally {
                lock.unlock();
            }
        }
    }

    private static List<User> userList = new ArrayList<>();

    public static void main(String[] args) throws Exception {
        Test t=new Test();
        new Thread(new Runnable() {
            @Override
            public void run() {
                long startTime = Calendar.getInstance().getTimeInMillis();
                System.out.println("------->开始执行:thread:" + Thread.currentThread().getId() + "   userSize:" + userList.size() + "  execute time:" + Long.toString(startTime));
                t.addUser();
                long endTime = Calendar.getInstance().getTimeInMillis();
                System.out.println("------->结束执行:thread:" + Thread.currentThread().getId() + "   userSize:" + userList.size() + "  execute time:" + endTime + "  take Time:" + (endTime - startTime));
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                long startTime = Calendar.getInstance().getTimeInMillis();
                System.out.println("------->开始执行:thread:" + Thread.currentThread().getId() + "   userSize:" + userList.size() + "  execute time:" + startTime);
                t.addUser();
                long endTime = Calendar.getInstance().getTimeInMillis();
                System.out.println("------->结束执行:thread:" + Thread.currentThread().getId() + "   userSize:" + userList.size() + "  execute time:" + endTime + "  take Time:" + (endTime - startTime));
            }
        }).start();


    }

}
 
 
运行结果:
------->开始执行:thread:13   userSize:0  execute time:1462334099726
------->开始执行:thread:12   userSize:0  execute time:1462334099726
------->结束执行:thread:13   userSize:1  execute time:1462334104736  take Time:5010
------->结束执行:thread:12   userSize:2  execute time:1462334109736  take Time:10010

   例4:tryLock实例:

   

package com.example;

import com.example.bean.User;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Random;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author xuanyouwu
 * @email [email protected]
 * @time 2016-05-04 11:09
 */
public class LockClass {
    public static class Test {
        Lock lock = new ReentrantLock();

  
        public void addUser2() {
            if (lock.tryLock()) {
                try {
                    User user = new User("name:" + System.currentTimeMillis(), new Random().nextInt(100));
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                    }
                    userList.add(user);
                } finally {
                    lock.unlock();
                }
            }
        }
    }

    private static List<User> userList = new ArrayList<>();

    public static void main(String[] args) throws Exception {
        Test t = new Test();
        new Thread(new Runnable() {
            @Override
            public void run() {
                long startTime = Calendar.getInstance().getTimeInMillis();
                System.out.println("------->开始执行:thread:" + Thread.currentThread().getId() + "   userSize:" + userList.size() + "  execute time:" + Long.toString(startTime));
                t.addUser2();
                long endTime = Calendar.getInstance().getTimeInMillis();
                System.out.println("------->结束执行:thread:" + Thread.currentThread().getId() + "   userSize:" + userList.size() + "  execute time:" + endTime + "  take Time:" + (endTime - startTime));
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                long startTime = Calendar.getInstance().getTimeInMillis();
                System.out.println("------->开始执行:thread:" + Thread.currentThread().getId() + "   userSize:" + userList.size() + "  execute time:" + startTime);
                t.addUser2();
                long endTime = Calendar.getInstance().getTimeInMillis();
                System.out.println("------->结束执行:thread:" + Thread.currentThread().getId() + "   userSize:" + userList.size() + "  execute time:" + endTime + "  take Time:" + (endTime - startTime));
            }
        }).start();


    }

}

运行结果:

------->开始执行:thread:13   userSize:0  execute time:1462334850764
------->开始执行:thread:12   userSize:0  execute time:1462334850764
------->结束执行:thread:12   userSize:0  execute time:1462334850773  take Time:9
------->结束执行:thread:13   userSize:1  execute time:1462334855774  take Time:5010                


    例5:tryLock(time)实例:

package com.example;

import com.example.bean.User;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author xuanyouwu
 * @email [email protected]
 * @time 2016-05-04 11:09
 */
public class LockClass {
    public static class Test {
        Lock lock = new ReentrantLock();

     

        public void addUser3() {
            try {
                if (lock.tryLock(6, TimeUnit.SECONDS)) {
                    try {
                        User user = new User("name:" + System.currentTimeMillis(), new Random().nextInt(100));
                        try {
                            Thread.sleep(5000);
                        } catch (InterruptedException e) {
                        }
                        userList.add(user);
                    } finally {
                        lock.unlock();
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private static List<User> userList = new ArrayList<>();

    public static void main(String[] args) throws Exception {
        Test t = new Test();
        new Thread(new Runnable() {
            @Override
            public void run() {
                long startTime = Calendar.getInstance().getTimeInMillis();
                System.out.println("------->开始执行:thread:" + Thread.currentThread().getId() + "   userSize:" + userList.size() + "  execute time:" + Long.toString(startTime));
                t.addUser3();
                long endTime = Calendar.getInstance().getTimeInMillis();
                System.out.println("------->结束执行:thread:" + Thread.currentThread().getId() + "   userSize:" + userList.size() + "  execute time:" + endTime + "  take Time:" + (endTime - startTime));
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                long startTime = Calendar.getInstance().getTimeInMillis();
                System.out.println("------->开始执行:thread:" + Thread.currentThread().getId() + "   userSize:" + userList.size() + "  execute time:" + startTime);
                t.addUser3();
                long endTime = Calendar.getInstance().getTimeInMillis();
                System.out.println("------->结束执行:thread:" + Thread.currentThread().getId() + "   userSize:" + userList.size() + "  execute time:" + endTime + "  take Time:" + (endTime - startTime));
            }
        }).start();


    }

}


运行结果:

------->开始执行:thread:13   userSize:0  execute time:1462336448589
------->开始执行:thread:12   userSize:0  execute time:1462336448589
------->结束执行:thread:13   userSize:1  execute time:1462336453600  take Time:5011
------->结束执行:thread:12   userSize:2  execute time:1462336458600  take Time:10011

  例6:

    public void addUser4() {
            try {
                lock.lockInterruptibly();
                User user = new User("name:" + System.currentTimeMillis(), new Random().nextInt(100));
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                }
                userList.add(user);
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
        }


你可能感兴趣的:(java ReentrantLock与synchronized)