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
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(); } }