文章目录
2.7 线程锁
-
synchronized
-
<mark>Lock</mark>(更快)
- ReentrantLock
- ReentrantReadWriteLock
- ReadLock
- WriteLock
- 方法:
- lock()
- unlock()
-
重入 reentrant
- 调用同一锁定代码,可以再次进入
- synchronized 可重入
- ReentrantLock 可重入
-
<mark>读</mark>锁和<mark>写</mark>锁
- <mark>读</mark>锁是一种<mark>共享</mark>锁
- 可以被多个线程同时,同时访问数据
- 可以提高访问数据的并发性能
- <mark>写</mark>锁
- 排他锁,<mark>只能被一个线程</mark>获得
- <mark>读</mark>锁是一种<mark>共享</mark>锁
-
Lock 底层原理
- 原子操作工具
- AtomicInteger
- AtomicLong
- AtomicReference
- …
- CAS
- Compare And Swap
- CAS算法,用非阻塞的方式,来获得锁
- 自旋锁
- 占用cpu资源
- 用忙循环,用CAS来获得锁
- 原子操作工具
2.7.1 悲观锁和乐观锁
<mark>悲观锁</mark>:还是像它的名字一样,对于并发间操作产生的线程安全问题持悲观状态,悲观锁认为竞争总是会发生,因此每次对某资源进行操作时,都会持有一个独占的锁,就像synchronized,不管三七二十一,直接上了锁就操作资源了。
<mark>乐观锁</mark>:就像它的名字一样,对于并发间操作产生的线程安全问题持乐观状态,乐观锁认为竞争不总是会发生,因此它不需要持有锁,将比较-替换这两个动作作为一个原子操作尝试去修改内存中的变量,如果失败则表示发生冲突,那么就应该有相应的重试逻辑。
2.7.2 两种常见的锁
-
<mark>Synchronized 互斥锁(悲观锁,有罪假设)</mark>
- 采用synchronized修饰符实现的同步机制叫做互斥锁机制,它所获得的锁叫做互斥锁。每个对象都有一个monitor(锁标记),当线程拥有这个锁标记时才能访问这个资源,没有锁标记便进入锁池。任何一个对象系统都会为其创建一个互斥锁,这个锁是为了分配给线程的,防止打断原子操作。每个对象的锁只能分配给一个线程,因此叫做互斥锁。
-
<mark>ReentrantReadWriteLock 读写锁(乐观锁,无罪假设)</mark>
- ReentrantLock是排他锁,排他锁在同一时刻仅有一个线程可以进行访问,实际上独占锁是一种相对比较保守的锁策略,在这种情况下任何“读/读”、“读/写”、“写/写”操作都不能同时发生,这在一定程度上降低了吞吐量。然而读操作之间不存在数据竞争问题,如果”读/读”操作能够以共享锁的方式进行,那会进一步提升性能。因此引入了ReentrantReadWriteLock,顾名思义,ReentrantReadWriteLock是Reentrant(可重入)Read(读)Write(写)Lock(锁),我们下面称它为读写锁。
- 读写锁内部又分为读锁和写锁,读锁可以在没有写锁的时候被多个线程同时持有,写锁是独占的。读锁和写锁分离从而提升程序性能,读写锁主要应用于读多写少的场景。
两种“锁的对比”
package cn.edut.com.tarena;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class Test04_reentrantLock {
static char[] a = {'*','*','*','*','*','*','*','*','*'};
static ReentrantReadWriteLock lock = new ReentrantReadWriteLock() ;
static char c = '-';
public static void main(String[] args) {
new Thread() {
@Override
public void run() {
while(true) {
//synchronized (a) {
lock.writeLock().lock();
for(int i=0 ; i<a.length ; i++) {
a[i] = c ;
}
c = c=='*'?'-':'*';
lock.writeLock().unlock();
//}
}
}
}.start();
new Thread() {
@Override
public void run() {
while(true) {
//synchronized (a) {
lock.readLock().lock();
System.out.println(a);
lock.readLock().unlock();
//}
}
}
}.start();
}
}
synchronize 测试
RenntrantWriteReadLock 测试
∗∗学反射前知识∗∗
.class在方法中存储的数据,的调用名称:
- Field = 》 成员变量
- Constructor =》 构造方法
- Method = 》 成员方法
1.1 反射 Reflect
文本配置文件
day15.A;a
day15.B;b
day15.C;c
要根据配置文件配置的流程,来执行
加载到方法区的“类对象”的反射操作,可以
- 获得一个类的定义信息
- 反射新建实例
- 反射调用成员
1.1.1 获取“类对象”
- 通过Class类获取:Class.forName(“day1801.A”)
- 通过已加载类获取:A.class
- 通过实例获取:a1.getClass()
forName 测试
package cn.edut.com.tarena;
public class Test05_forName {
public static void main(String[] args) throws Exception {
String name = "cn/edut/com/tarena/Test00" ;
name = name.replace("/" , "." ) ;
Class<?> test = Class.forName(name);
System.out.println(test.getName());
}
}
1.1.3 获取<mark>成员变量</mark>定义<mark>信息</mark>
获得所有公开的成员变量,包括继承的变量
getFields()
获得本类定义的成员变量,包括私有
不包括继承的变量
getDeclaredFields()
getField(变量名)
getDeclaredField(变量名)
1.1.4 获取<mark>构造方法</mark>定义<mark>信息</mark>
获得所有公开的构造方法
getConstructors()
获得所有构造方法,包括私有
getDeclaredConstructors()
getConstructor(参数类型列表)
getDeclaredConstructor(int.class, String.class)
<mark>指定参数依次为 int 和 String 的构造方法</mark>
1.1.5 获取<mark>方法</mark>定义<mark>信息</mark>
获得所有可见的方法,包括继承的方法
getMethods()
获得本类定义的方法,包括私有
不包括继承的方法
getDeclaredMethods()
getMethod(方法名,参数类型列表)
getDeclaredMethod(方法名, int.class, String.class)
类
package cn.edut.com.tarena;
public class Test00 {
public int a = 100;
protected String b = "adfa";
Integer c = new Integer(60);
private D<D<Integer>> d = new D<>();
public Test00() {
}
public Test00(int a ) {
this.a = a ;
}
public Test00(String b , int a ) {
}
public Test00(int a , D<Integer> c) {
}
private void a(int a ) {};
protected String b(String c) {return "bbb";}
void c() {};
public D d() {return new D();}
}
class D<T> {}
测试
package cn.edut.com.tarena;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
public class Test05_forName {
public static void main(String[] args) throws Exception {
String name = "cn/edut/com/tarena/Test00" ;
name = name.replace("/" , "." ) ;
Class<?> test = Class.forName(name);
System.out.println("---包名类名-----------------");
showPackage(test);
System.out.println("---成员变量名-----------------");
showFields(test);
System.out.println("---构造方法-----------------");
showConstructor(test);
System.out.println("---包名类名-----------------");
showMethod(test) ;
}
private static void showMethod(Class<?> test) {
Method[] methods = test.getDeclaredMethods();
for(Method m : methods ) {
System.out.println(m);
}
}
private static void showConstructor(Class<?> test) {
Constructor<?>[] constructors = test.getDeclaredConstructors();
for(Constructor<?> c : constructors) {
String className = test.getSimpleName();
System.out.println(className+" "+Arrays.toString(c.getParameters()));
System.out.println(c.toString());
System.out.println("。 。 。 。 。 。 ");
}
}
private static void showFields(Class<?> test) {
/* * Field封装成员变量的定义信息 * * private static final int a */
Field[] a = test.getDeclaredFields();
for (Field f : a) {
String type = f.getType().getSimpleName();
String name = f.getName();
System.out.println(type+" "+name);
System.out.println(f);
System.out.println("。 。 。 。 。 。 ");
}
}
private static void showPackage(Class<?> test) {
System.out.println(test.getName());
}
}
结果:
—包名类名-----------------
cn.edut.com.tarena.Test00
—成员变量名-----------------
int a
public int cn.edut.com.tarena.Test00.a
。 。 。 。 。 。
String b
protected java.lang.String cn.edut.com.tarena.Test00.b
。 。 。 。 。 。
Integer c
java.lang.Integer cn.edut.com.tarena.Test00.c
。 。 。 。 。 。
D d
private cn.edut.com.tarena.D cn.edut.com.tarena.Test00.d
。 。 。 。 。 。
—构造方法-----------------
Test00 [int arg0, cn.edut.com.tarena.D<java.lang.Integer> arg1]
public cn.edut.com.tarena.Test00(int,cn.edut.com.tarena.D)
。 。 。 。 。 。
Test00 [java.lang.String arg0, int arg1]
public cn.edut.com.tarena.Test00(java.lang.String,int)
。 。 。 。 。 。
Test00 [int arg0]
public cn.edut.com.tarena.Test00(int)
。 。 。 。 。 。
Test00 []
public cn.edut.com.tarena.Test00()
。 。 。 。 。 。
—包名类名-----------------
void cn.edut.com.tarena.Test00.c()
protected java.lang.String cn.edut.com.tarena.Test00.b(java.lang.String)
private void cn.edut.com.tarena.Test00.a(int)
public cn.edut.com.tarena.D cn.edut.com.tarena.Test00.d()
1.1.6 反射<mark>新建实例</mark>
- 新建实例时,执行<mark>无参构造</mark>
Object obj = c.newInstance();
- 新建实例时,执行<mark>有参构造</mark>
获取构造方法 - 新建实例,并执行该构造方法
Constructor t = c.getConstructor(int.class, String.class);
Object obj = t.newInstance(6, "abc");
类
package cn.edut.com.tarena;
public class Test00 {
public int a = 100;
protected String b = "adfa";
private Integer c = new Integer(60);
D<D<Integer>> d = new D<>();
public Test00() {
}
public Test00(int a ) {
this.a = a ;
}
public Test00(String b , int a ) {
}
public Test00(int a , D<Integer> c) {
}
protected void a(int a ) {};
private String b(String c) {return c+"d";}
void c() {};
public D d() {return new D();}
}
class D<T> {}
测试方法
package cn.edut.com.tarena;
import java.lang.reflect.Constructor;
public class Test06_newInstance {
public static void main(String[] args) throws Exception {
System.out.println("---无参构造-----");
unparaConstructor();
System.out.println("---无参构造-----");
Constructor<Test00> constructor = Test00.class.getConstructor(int.class);
Test00 newInstance = constructor.newInstance(123456789);
System.out.println("a="+newInstance.a);
}
private static void unparaConstructor() throws Exception {
Test00 obj = Test00.class.newInstance();
System.out.println("a=" + obj.a);
}
}
1.1.7 反射调用<mark>成员变量</mark>
获取变量
Field f = c.getDeclaredField(变量名);
使私有成员允许访问
f.setAccessible(true);
反射给变量赋值
为指定实例的变量赋值。<mark>静态变量,第一参数给 null</mark>
f.set(实例, 值);
反射访问变量的值
访问指定实例的变量的值。<mark>静态变量,第一参数给 null</mark>
Object v = f.get(实例);
package cn.edut.com.tarena;
import java.lang.reflect.Field;
public class Test07_para {
public static void main(String[] args) throws Exception {
Class<Test00> s = Test00.class;
Test00 t1 = s.newInstance();
//获取变量
Field c = s.getDeclaredField("c");
c.setAccessible(true);
System.out.println("c="+c.get(t1));
c.set(t1, 99999);
System.out.println("c="+c.get(t1));
}
}
1.1.8 反射调用成员方法
获取方法
Method m = c.getDeclaredMethod(方法名, 参数类型列表);
使私有方法允许被调用
m.setAccessible(true)
反射调用方法
让指定的实例来执行该方法
Object returnValue = m.invoke(实例, 参数数据)
package cn.edut.com.tarena;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class Test08_method {
public static void main(String[] args) throws Exception {
//class类
Class<Test00> t = Test00.class ;
//含参构造
Constructor<Test00> constructor1 = t.getConstructor(int.class);
//实例
Test00 test1 = constructor1.newInstance(100);
Method b_Method = t.getDeclaredMethod("b", String.class);
b_Method.setAccessible(true);
Object result = b_Method.invoke(test1, "abc");
System.out.println(result);
}
}