今天练习了Java的多线程,提到多线程就基本就会用到锁
Java通过关键字及几个类实现了锁的机制,这里先介绍下Java都有哪些锁:
一、Java实现锁的机制:
Java运行到包含锁的代码时,获取尝试获取对应的锁,如果锁被其他线程占用着,则该线程默认等待,待这个锁得以释放在去获取,进而执行锁中的代码。
注:这里说的尝试获取对应的锁是指当多个线程公用一个锁的时候。
二、锁的种类
Java总共就两个锁:对象锁和类锁
区别:
具体这里分为了对象锁和类锁,是因为锁作用的范围不同,如果多个线程采用的是对象锁,需要要求他们引用同一个对象实例的锁才起作用,一旦一个线程使用的是不同的对象实例,就不受这个锁的干预了,但是类锁不同,类锁对应的是class对象,这个类的所有实例对应一个class对象,所以他们相当于争抢同一个锁。
对象锁:
说到对象锁,需要在这了统一一个认识:Java里的所有代码都是对对象执行的操作
其实每个对象都有一个锁,只不过对于没有加锁的代码而言,他们对这个锁视而不见,因为普通代码的执行根本就不依赖锁。
对象锁的具体表现形式是:
- 对方法加的锁
- 代码块加的锁
对方法加的锁长这样:
public synchronized void output1() {
for(int i=0;i<10;i++) {
System.out.println(Thread.currentThread().getName());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行结果如下:
Synchronized test
thread1
thread1
thread1
thread1
thread1
thread1
thread1
thread1
thread1
thread1
thread2
thread2
thread2
thread2
thread2
thread2
thread2
thread2
thread2
thread2
对代码块加的锁长这样:
public void output2() {
for(int i=0;i<1;i++) {
System.out.println(Thread.currentThread().getName() + "---read");
}
synchronized(Synchronized_test.syn) {
for(int i=0;i<10;i++) {
System.out.println(Thread.currentThread().getName() + "--- write");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
运行结果如下:
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
@Override
public void run() {
lock.lock();
for(int i=1;i<10;i++) {
System.out.println(Thread.currentThread().getName());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
lock.unlock();
}
运行结果如下:
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
- 实现中断线程
public class Lock_interrupt_test implements Runnable {
private Lock lock = null;
public Lock_interrupt_test() {
lock = new ReentrantLock();
} @Override
public void run() {
try {
lock.lockInterruptibly();
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName());
Thread.sleep(100);
}
} catch (InterruptedException e1) {
e1.printStackTrace();
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
System.out.println("lock interrupt test");
Lock_interrupt_test lock_interrupt_test = new
Lock_interrupt_test();
Thread thread1 = new Thread(lock_interrupt_test, "thread1");
Thread thread2 = new Thread(lock_interrupt_test, "thread2");
thread1.start();
thread2.start();
try {
Thread.sleep(400);
} catch (InterruptedException e) {
e.printStackTrace();
}
State state1 = thread1.getState();
Thread thread = state1.toString().equals("TIMED_WAITING")?
thread1:thread2;
System.out.println("interrupt " + thread.getName());
thread.interrupt();
}
}
运行结果如下:
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
- 实现检测锁状态
@Override
public void run() {
try {
if (lock.tryLock(400,TimeUnit.MILLISECONDS)) {
System.out.println(Thread.currentThread().getName() + " have get the lock");
for (int i = 1; i < 10; i++) {
System.out.println(Thread.currentThread().getName());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + " have
return the lock");
lock.unlock();
}
else {
for (int i = 1; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + " locking");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
运行结果如下:
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的用法
实现读写分离锁:
@Override
public void run() {
lock.readLock().lock();
for(int i=0;i<10;i++) {
System.out.println(Thread.currentThread().getName() + "---read");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
lock.readLock().unlock();
lock.writeLock().lock();
for(int i=0;i<10;i++) {
System.out.println(Thread.currentThread().getName() + "---write");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
lock.writeLock().unlock();
}
运行结果如下:
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