Java的锁
今天练习了Java的多线程,提到多线程就基本就会用到锁
Java通过关键字及几个类实现了锁的机制,这里先介绍下Java都有哪些锁:
一、Java实现锁的机制:
Java运行到包含锁的代码时,获取尝试获取对应的锁,如果锁被其他线程占用着,则该线程默认等待,待这个锁得以释放在去获取,进而执行锁中的代码。
注:这里说的尝试获取对应的锁是指当多个线程公用一个锁的时候。
二、锁的种类
Java总共就两个锁:对象锁和类锁
区别:
具体这里分为了对象锁和类锁,是因为锁作用的范围不同,如果多个线程采用的是对象锁,需要要求他们引用同一个对象实例的锁才起作用,一旦一个线程使用的是不同的对象实例,就不受这个锁的干预了,但是类锁不同,类锁对应的是class对象,这个类的所有实例对应一个class对象,所以他们相当于争抢同一个锁。
对象锁:
说到对象锁,需要在这了统一一个认识:Java里的所有代码都是对对象执行的操作
其实每个对象都有一个锁,只不过对于没有加锁的代码而言,他们对这个锁视而不见,因为普通代码的执行根本就不依赖锁。
对象锁的具体表现形式是:
- 对方法加的锁
- 代码块加的锁
对方法加的锁长这样:
1 public synchronized void output1() { 2 for(int i=0;i<10;i++) { 3 System.out.println(Thread.currentThread().getName()); 4 try { 5 Thread.sleep(100); 6 } catch (InterruptedException e) { 7 e.printStackTrace(); 8 } 9 } 10 }
运行结果如下:
Synchronized test
thread1
thread1
thread1
thread1
thread1
thread1
thread1
thread1
thread1
thread1
thread2
thread2
thread2
thread2
thread2
thread2
thread2
thread2
thread2
thread2
对代码块加的锁长这样:
1 public void output2() { 2 for(int i=0;i<1;i++) { 3 System.out.println(Thread.currentThread().getName() + "---read"); 4 } 5 synchronized(Synchronized_test.syn) { 6 for(int i=0;i<10;i++) { 7 System.out.println(Thread.currentThread().getName() + "--- write"); 8 try { 9 Thread.sleep(100); 10 } catch (InterruptedException e) { 11 e.printStackTrace(); 12 } 13 } 14 } 15 }
运行结果如下:
Synchronized test
thread1---read
thread2---read
thread1---write
thread1---write
thread1---write
thread1---write
thread1---write
thread1---write
thread1---write
thread1---write
thread1---write
thread1---write
thread2---write
thread2---write
thread2---write
thread2---write
thread2---write
thread2---write
thread2---write
thread2---write
thread2---write
thread2—write
实现原理:
具体的实现方式是,当程序运行到包含锁的代码的时候,不管是方法还是代码块,线程会拿到锁域里的所有对象的锁。如果有方法调用也会递归式的获取。
类锁
类锁一半针对静态代码块或者静态方法。例子这里就不写了,就是相当于在上面两个例子前面加个static关键字。
只要是调用这个类的方法,引用类锁的线程争抢的就都是一把锁。
三、关于锁的关键字:
synchronized
注:可以指定方法,可以指定代码块
四、实现锁的类
1. ReentrantLock
2. ReentrantReadWriteLock
这两种锁和synchronized关键字的区别:
- 当锁被其他线程获取,当前线程可以不必阻塞住。
- 关键字的方式是由系统自动释放锁,而下面必须要手动操作。
ReentranLock的用法
- 简单的用法如下,功能同关键字synchronized
1 @Override 2 public void run() { 3 lock.lock(); 4 for(int i=1;i<10;i++) { 5 System.out.println(Thread.currentThread().getName()); 6 try { 7 Thread.sleep(100); 8 } catch (InterruptedException e) { 9 e.printStackTrace(); 10 } 11 } 12 lock.unlock(); 13 }
运行结果如下:
lock test Thread-0 Thread-0 Thread-0 Thread-0 Thread-0 Thread-0 Thread-0 Thread-0 Thread-0 Thread-1 Thread-1 Thread-1 Thread-1 Thread-1 Thread-1 Thread-1 Thread-1 Thread-1
- 实现中断线程
1 public class Lock_interrupt_test implements Runnable { 2 private Lock lock = null; 3 public Lock_interrupt_test() { 4 lock = new ReentrantLock(); 5 } 6 7 @Override 8 public void run() { 9 try { 10 lock.lockInterruptibly(); 11 for (int i = 0; i < 10; i++) { 12 System.out.println(Thread.currentThread().getName()); 13 Thread.sleep(100); 14 } 15 } catch (InterruptedException e1) { 16 e1.printStackTrace(); 17 } finally { 18 lock.unlock(); 19 } 20 } 21 public static void main(String[] args) { 22 System.out.println("lock interrupt test"); 23 Lock_interrupt_test lock_interrupt_test = new 24 Lock_interrupt_test(); 25 Thread thread1 = new Thread(lock_interrupt_test, "thread1"); 26 Thread thread2 = new Thread(lock_interrupt_test, "thread2"); 27 thread1.start(); 28 thread2.start(); 29 try { 30 Thread.sleep(400); 31 } catch (InterruptedException e) { 32 e.printStackTrace(); 33 } 34 State state1 = thread1.getState(); 35 Thread thread = state1.toString().equals("TIMED_WAITING")? 36 thread1:thread2; 37 System.out.println("interrupt " + thread.getName()); 38 thread.interrupt(); 39 } 40 }
运行结果如下:
lock interrupt test thread1 thread1 thread1 thread1 interrupt thread1 java.lang.InterruptedException: sleep interrupted at java.base/java.lang.Thread.sleep(Native Method) at lock_type.Lock_interrupt_test.run(Lock_interrupt_test.java:21) at java.base/java.lang.Thread.run(Thread.java:844) thread2 thread2 thread2 thread2 thread2 thread2 thread2 thread2 thread2 thread2
- 实现检测锁状态
1 @Override 2 public void run() { 3 try { 4 if (lock.tryLock(400,TimeUnit.MILLISECONDS)) { 5 System.out.println(Thread.currentThread().getName() + " have get the lock"); 6 for (int i = 1; i < 10; i++) { 7 System.out.println(Thread.currentThread().getName()); 8 try { 9 Thread.sleep(100); 10 } catch (InterruptedException e) { 11 e.printStackTrace(); 12 } 13 } 14 System.out.println(Thread.currentThread().getName() + " have 15 return the lock"); 16 lock.unlock(); 17 } 18 else { 19 for (int i = 1; i < 10; i++) { 20 System.out.println(Thread.currentThread().getName() + " locking"); 21 try { 22 Thread.sleep(100); 23 } catch (InterruptedException e) { 24 e.printStackTrace(); 25 } 26 } 27 } 28 } catch (InterruptedException e) { 29 e.printStackTrace(); 30 } 31 }
运行结果如下:
lock try test Thread-0 have get the lock Thread-0 Thread-0 Thread-0 Thread-0 Thread-1 locking Thread-0 Thread-1 locking Thread-0 Thread-1 locking Thread-0 Thread-1 locking Thread-0 Thread-1 locking Thread-0 Thread-1 locking Thread-0 have return the lock Thread-1 locking Thread-1 locking Thread-1 locking
ReentrantReadWriteLock的用法
实现读写分离锁:
1 @Override 2 public void run() { 3 lock.readLock().lock(); 4 for(int i=0;i<10;i++) { 5 System.out.println(Thread.currentThread().getName() + "---read"); 6 try { 7 Thread.sleep(100); 8 } catch (InterruptedException e) { 9 e.printStackTrace(); 10 } 11 } 12 lock.readLock().unlock(); 13 lock.writeLock().lock(); 14 for(int i=0;i<10;i++) { 15 System.out.println(Thread.currentThread().getName() + "---write"); 16 try { 17 Thread.sleep(100); 18 } catch (InterruptedException e) { 19 e.printStackTrace(); 20 } 21 } 22 lock.writeLock().unlock(); 23 }
运行结果如下:
lock read write test
thread2---read
thread1---read
thread1---read
thread2---read
thread1---read
thread2---read
thread2---read
thread1---read
thread1---read
thread2---read
thread1---read
thread2---read
thread1---read
thread2---read
thread1---read
thread2---read
thread2---read
thread1---read
thread2---read
thread1---read
thread1---write
thread1---write
thread1---write
thread1---write
thread1---write
thread1---write
thread1---write
thread1---write
thread1---write
thread1---write
thread2---write
thread2---write
thread2---write
thread2---write
thread2---write
thread2---write
thread2---write
thread2---write
thread2---write
thread2---write