hadoop07---synchronized,lock
synchronized 锁是jvm控制的,控制锁住的代码块只能有一个线程进入。线程执行完了锁自动释放,抛出异常jvm会释放锁。 synchronized的缺陷 1.如果一个线程被阻塞了,其余的线程就要一直等下去,Lock可以在线程阻塞的时候其他线程不用一直等下去。 2.同时读文件时候,其他线程也要等待,lock可以做到读的时候不加锁,写的时候枷锁。 3.synchronized不知道线程有没有成功获取到锁。Lock可以知道线程有没有成功获取到锁。
package cn.itcast_01_mythread.thread.testThread; public class MySynchronized { // synchronized也可以放在方法上面 public static void main(String[] args) { final MySynchronized mySynchronized = new MySynchronized(); final MySynchronized mySynchronized2 = new MySynchronized(); new Thread("thread1") { public void run() { synchronized (mySynchronized) { try { System.out.println(this.getName()+" start"); int i =1/0; //如果发生异常,jvm会将锁释放 Thread.sleep(5000); System.out.println(this.getName()+"醒了"); System.out.println(this.getName()+" end"); } catch (InterruptedException e) { e.printStackTrace(); } } } }.start(); new Thread("thread2") { public void run() { synchronized (mySynchronized) { //争抢同一把锁时,线程1没释放之前,线程2只能等待 // synchronized (mySynchronized2) { //如果不是一把锁,可以看到两句话同时打印 System.out.println(this.getName()+" start"); System.out.println(this.getName()+" end"); } } }.start(); } }
lock和synchronized的区别 1)synchronized是Java 内置特性,Lock不是。 2)synchronized不需要手动释放锁,代码块执行完或者抛出异常jvm会自动释放锁;Lock要手动释放锁,如果没有释放锁可能死锁。
java.util.concurrent.locks包下常用的类 首先要说明的就是Lock,通过查看Lock的源码可知,Lock是一个接口: public interface Lock { void lock(); void lockInterruptibly() throws InterruptedException; boolean tryLock(); boolean tryLock(long time, TimeUnit unit) throws InterruptedException; void unlock(); }
Lock接口中每个方法的使用: lock()、tryLock()、tryLock(long time, TimeUnit unit)、lockInterruptibly()是用来获取锁的。 unLock()方法是用来释放锁的。
四个获取锁方法的区别: lock()方法是平常使用得最多的一个方法,就是用来获取锁。如果锁已被其他线程获取,则进行等待。 由于在前面讲到如果采用Lock,必须主动去释放锁,并且在发生异常时,不会自动释放锁。因此一般来说,使用Lock必须在try{}catch{}块中进行,并且将释放锁的操作放在finally块中进行,以保证锁一定被被释放,防止死锁的发生。
tryLock()方法是有返回值的,它表示用来尝试获取锁,如果获取成功,则返回true,如果获取失败(即锁已被其他线程获取),则返回false,也就说这个方法无论如何都会立即返回。在拿不到锁时不会一直在那等待。不等待。
tryLock(long time, TimeUnit unit)方法和tryLock()方法是类似的,尝试获取锁。只不过区别在于这个方法在拿不到锁时会等待一定的时间,在时间期限之内如果还拿不到锁,就返回false。如果如果一开始拿到锁或者在等待期间内拿到了锁,则返回true。异步过程,获取不到锁就去做别的,过一会再来获取锁。
lockInterruptibly()方法比较特殊,当通过这个方法去获取锁时,如果线程正在等待获取锁,则这个线程能够响应中断,即中断线程的等待状态。也就使说,当两个线程同时通过lock.lockInterruptibly()想获取某个锁时,假若此时线程A获取到了锁,而线程B只有等待,那么对线程B调用自己的threadB.interrupt()方法能够中断线程B的等待过程。等的人自己可以中断,不是获取到锁的人中断。synchronized时候等的人一直等待,不会跳出等待,一直等着。
当一个线程获取了锁之后,是不会被自己interrupt()方法中断的。
因此当通过lockInterruptibly()方法获取某个锁时,如果不能获取到,只有进行等待的情况下,是可以响应中断的。
package cn.itcast_01_mythread.thread.lock; import java.util.ArrayList; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class MyLockTest { private static ArrayList<Integer> arrayList = new ArrayList<Integer>(); static Lock lock = new ReentrantLock(); // 注意这个地方 public static <E> void main(String[] args) { new Thread() { public void run() { Thread thread = Thread.currentThread(); lock.lock();//获取锁,用的是同一把锁 try { System.out.println(thread.getName() + "得到了锁"); for (int i = 0; i < 5; i++) { arrayList.add(i); } } catch (Exception e) { // TODO: handle exception } finally { System.out.println(thread.getName() + "释放了锁"); lock.unlock(); } }; }.start(); new Thread() { public void run() { Thread thread = Thread.currentThread(); lock.lock();//获取锁,用的是同一把锁 try { System.out.println(thread.getName() + "得到了锁"); for (int i = 0; i < 5; i++) { arrayList.add(i); } } catch (Exception e) { // TODO: handle exception } finally { System.out.println(thread.getName() + "释放了锁"); lock.unlock(); } }; }.start(); } /*Thread-0得到了锁 Thread-0释放了锁 Thread-1得到了锁 Thread-1释放了锁*/ }
package cn.itcast_01_mythread.thread.lock; import java.util.ArrayList; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * 尝试获取锁。观察现象:一个线程获得锁后,另一个线程取不到锁,不会一直等待 * @author * */ public class MyTryLock { private static ArrayList<Integer> arrayList = new ArrayList<Integer>(); static Lock lock = new ReentrantLock(); // 注意这个地方 public static void main(String[] args) { new Thread() { public void run() { Thread thread = Thread.currentThread(); //run方法里面可以获取到当前线程 boolean tryLock = lock.tryLock();//尝试获取锁,如果其他线程已经获取到锁,这里就不获取了。 System.out.println(thread.getName()+" "+tryLock); if (tryLock) { try { System.out.println(thread.getName() + "得到了锁"); for (int i = 0; i < 5; i++) { arrayList.add(i); } } catch (Exception e) { // TODO: handle exception } finally { System.out.println(thread.getName() + "释放了锁"); lock.unlock(); } } }; }.start(); new Thread() { /* (non-Javadoc) * @see java.lang.Thread#run() */ public void run() { Thread thread = Thread.currentThread(); boolean tryLock = lock.tryLock(); System.out.println(thread.getName()+" "+tryLock); if (tryLock) { try { System.out.println(thread.getName() + "得到了锁"); for (int i = 0; i < 5; i++) { arrayList.add(i); } } catch (Exception e) { // TODO: handle exception } finally { System.out.println(thread.getName() + "释放了锁"); lock.unlock(); } } }; }.start(); } }
package cn.itcast_01_mythread.thread.lock; import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * 可中断锁。观察现象:如果thread-0得到了锁,阻塞。。。thread-1尝试获取锁,如果拿不到,则可以被中断等待 * @author * */ public class MyInterruptibly { private Lock lock = new ReentrantLock(); public static void main(String[] args) { MyInterruptibly test = new MyInterruptibly(); MyThread thread0 = new MyThread(test); MyThread thread1 = new MyThread(test); thread0.start(); thread1.start(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } thread1.interrupt();//thread1拿到锁就不能中断了 System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+"====================="); } public void insert(Thread thread) throws InterruptedException{ System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+thread.getName()+"进来了"); //2个线程都调用lockInterruptibly获取锁,一个线程获取到锁后睡眠,另一个线程可以被中断。 //lockInterruptibly获取锁的方法,这个获取锁的方法是可以被中断的,中断的时候抛出InterruptedException异常。 lock.lockInterruptibly(); //注意,如果需要正确中断等待锁的线程,必须将获取锁放在外面,然后将InterruptedException抛出 try { System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+thread.getName()+"得到了锁"); long startTime = System.currentTimeMillis(); Thread.sleep(15000); /*for( ; ;) { if(System.currentTimeMillis() - startTime >= Integer.MAX_VALUE)//Integer.MAX_VALUE相当于阻塞 break; //插入数据, }*/ } finally { System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+Thread.currentThread().getName()+"执行finally"); lock.unlock(); System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+thread.getName()+"释放了锁"); } } } class MyThread extends Thread { private MyInterruptibly test = null; public MyThread(MyInterruptibly test) { this.test = test; } @Override public void run() { try { test.insert(Thread.currentThread());//run方法里面可以获取到当前线程 } catch (Exception e) { System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+Thread.currentThread().getName()+"被中断"); } } } /*2018-05-08 11:14:59Thread-0进来了 2018-05-08 11:14:59Thread-1进来了 2018-05-08 11:14:59Thread-0得到了锁 2018-05-08 11:15:01===================== 2018-05-08 11:15:01Thread-1被中断 2018-05-08 11:15:14Thread-0执行finally 2018-05-08 11:15:14Thread-0释放了锁*/ /*2018-05-08 11:19:06Thread-1进来了 2018-05-08 11:19:06Thread-0进来了 2018-05-08 11:19:06Thread-1得到了锁 2018-05-08 11:19:08=====================,Thread-1倍中断 2018-05-08 11:19:08Thread-1执行finally 2018-05-08 11:19:08Thread-1释放了锁 2018-05-08 11:19:08Thread-0得到了锁 2018-05-08 11:19:08Thread-1被中断 2018-05-08 11:19:23Thread-0执行finally 2018-05-08 11:19:23Thread-0释放了锁*/