作者:此女人不嫁_ | 来源:互联网 | 2023-10-09 19:43
JUC-共享模型之不可变一、不可变类设计二、final原理三、享元设计模式四、实现一个简单的连接池五、State一、不可变类设计不可变:如果一个对象不能够修改其内部
JUC-共享模型之不可变 一、不可变类设计 二、final 三、享元设计模式 四、实现一个简单的连接池 五、State
一、不可变类设计 不可变:如果一个对象不能够修改其内部状态 (属性),那么就是不可变对象
不可变对象线程安全 的,不存在并发修改和可见性问题 ,是另一种避免竞争的方式
String
类也是不可变的,该类和类中所有属性都是final
的
类用final
修饰保证了该类中的方法不能被覆盖 ,防止子类无意间破坏不可变性
无写入方法 (set)确保外部不能对内部属性进行修改
属性用final
修饰保证了该属性是只读的,不能修改
public final class String implements java. io. Serializable, Comparable < String > , CharSequence { private final char value[ ] ; }
更改 String 类数据时&#xff0c;会构造新字符串对象 &#xff0c;生成新的 char[] value&#xff0c;通过创建副本对象来避免共享的方式称之为保护性拷贝
二、final 原理 public class TestFinal { final int a &#61; 20 ; }
字节码&#xff1a;
0 : aload_01 : invokespecial #1 4 : aload_05 : bipush 20 7 : putfield #2 < -- 写屏障10 : return
final 变量的赋值通过 putfield 指令来完成&#xff0c;在这条指令之后也会加入写屏障
&#xff0c;保证在其它线程读到它的值时不会出现为 0 的情况
其他线程访问 final 修饰的变量会复制一份放入栈中 &#xff0c;效率更高
三、享元设计模式 简介定义英文名称&#xff1a;Flyweight pattern, 重用数量有限的同一类对象。 享元模式的体现:
1、在JDK中Boolean&#xff0c;Byte&#xff0c;Short&#xff0c;Integer&#xff0c;Long&#xff0c;Character等包装类 提供了valueOf方法
&#xff0c;例如 Long 的valueOf会缓存-128~127之间的 Long 对象 &#xff0c;在这个范围之间会重用对象&#xff0c;大于这个范围&#xff0c;才会新建 Long 对象
public static Long valueOf ( long l) { final int offset &#61; 128 ; if ( l >&#61; - 128 && l <&#61; 127 ) { return LongCache . cache[ ( int ) l &#43; offset] ; } return new Long ( l) ; }
Byte, Short, Long 缓存的范围都是-128-127 Character 缓存的范围是 0-127 Boolean 缓存了 TRUE 和 FALSE Integer的默认范围是 -128~127&#xff0c;最小值不能变&#xff0c;但最大值可以通过调整虚拟机参数 "-Djava.lang.Integer.IntegerCache.high "来改变 2、String 串池 3、BigDecimal, BigInteger
四、实现一个简单的连接池 例如&#xff1a;一个线上商城应用&#xff0c;QPS 达到数千&#xff0c;如果每次都重新创建和关闭数据库连接&#xff0c;性能会受到极大影响。 这时预先创建好一批连接&#xff0c;放入连接池。一次请求到达后&#xff0c;从连接池获取连接&#xff0c;使用完毕后再还回连接池 &#xff0c;这样既节约了连接的创建和关闭时间&#xff0c;也实现了连接的重用&#xff0c;不至于让庞大的连接数压垮数据库。
public class Test2 { public static void main ( String [ ] args) { Pool pool &#61; new Pool ( 2 ) ; for ( int i &#61; 0 ; i < 5 ; i&#43;&#43; ) { new Thread ( ( ) -> { Connection conn &#61; pool. borrow ( ) ; try { Thread . sleep ( new Random ( ) . nextInt ( 1000 ) ) ; } catch ( InterruptedException e) { e. printStackTrace ( ) ; } pool. free ( conn) ; } ) . start ( ) ; } } } &#64;Slf4j ( topic &#61; "guizy.Pool" ) class Pool { private final int poolSize; private Connection [ ] connections; private AtomicIntegerArray states; public Pool ( int poolSize) { this . poolSize &#61; poolSize; this . connections &#61; new Connection [ poolSize] ; this . states &#61; new AtomicIntegerArray ( new int [ poolSize] ) ; for ( int i &#61; 0 ; i < poolSize; i&#43;&#43; ) { connections[ i] &#61; new MockConnection ( "连接" &#43; ( i &#43; 1 ) ) ; } } public Connection borrow ( ) { while ( true ) { for ( int i &#61; 0 ; i < poolSize; i&#43;&#43; ) { if ( states. get ( i) &#61;&#61; 0 ) { if ( states. compareAndSet ( i, 0 , 1 ) ) { log. debug ( "borrow {}" , connections[ i] ) ; return connections[ i] ; } } } synchronized ( this ) { try { log. debug ( "wait..." ) ; this . wait ( ) ; } catch ( InterruptedException e) { e. printStackTrace ( ) ; } } } } public void free ( Connection conn) { for ( int i &#61; 0 ; i < poolSize; i&#43;&#43; ) { if ( connections[ i] &#61;&#61; conn) { states. set ( i, 0 ) ; synchronized ( this ) { log. debug ( "free {}" , conn) ; this . notifyAll ( ) ; } break ; } } } } class MockConnection implements Connection { private String name; public MockConnection ( String name) { this . name &#61; name; } &#64;Override public String toString ( ) { return "MockConnection{" &#43; "name&#61;&#39;" &#43; name &#43; &#39;\&#39;&#39; &#43; &#39;}&#39; ; } }
22 : 01 : 07.000 guizy. Pool [ Thread - 2 ] - wait. . . 22 : 01 : 07.000 guizy. Pool [ Thread - 0 ] - borrow MockConnection { name&#61; &#39;连接1&#39; } 22 : 01 : 07.005 guizy. Pool [ Thread - 4 ] - wait. . . 22 : 01 : 07.000 guizy. Pool [ Thread - 1 ] - borrow MockConnection { name&#61; &#39;连接2&#39; } 22 : 01 : 07.006 guizy. Pool [ Thread - 3 ] - wait. . . 22 : 01 : 07.099 guizy. Pool [ Thread - 0 ] - free MockConnection { name&#61; &#39;连接1&#39; } 22 : 01 : 07.099 guizy. Pool [ Thread - 2 ] - wait. . . 22 : 01 : 07.099 guizy. Pool [ Thread - 3 ] - borrow MockConnection { name&#61; &#39;连接1&#39; } 22 : 01 : 07.099 guizy. Pool [ Thread - 4 ] - wait. . . 22 : 01 : 07.581 guizy. Pool [ Thread - 3 ] - free MockConnection { name&#61; &#39;连接1&#39; } 22 : 01 : 07.582 guizy. Pool [ Thread - 2 ] - borrow MockConnection { name&#61; &#39;连接1&#39; } 22 : 01 : 07.582 guizy. Pool [ Thread - 4 ] - wait. . . 22 : 01 : 07.617 guizy. Pool [ Thread - 1 ] - free MockConnection { name&#61; &#39;连接2&#39; } 22 : 01 : 07.618 guizy. Pool [ Thread - 4 ] - borrow MockConnection { name&#61; &#39;连接2&#39; } 22 : 01 : 07.955 guizy. Pool [ Thread - 4 ] - free MockConnection { name&#61; &#39;连接2&#39; } 22 : 01 : 08.552 guizy. Pool [ Thread - 2 ] - free MockConnection { name&#61; &#39;连接1&#39; }
五、State 无状态 &#xff1a;成员变量保存的数据也可以称为状态信息&#xff0c;无状态就是没有成员变量
Servlet 为了保证其线程安全&#xff0c;一般不为 Servlet 设置成员变量&#xff0c;这种没有任何成员变量的类是线程安全的
参考&#xff1a;
Java并发编程(八) : 不可变对象设计(String保护性拷贝)、final的使用、享元模式 JUC-无锁