private final char value[]; public String replace(char oldChar, char newChar) { if (oldChar != newChar) { int len = value.length; int i = -1; char[] val = value; /* avoid getfield opcode */ while (++i < len) { if (val[i] == oldChar) { break; } } if (i < len) { char buf[] = new char[len]; for (int j = 0; j < i; j++) { buf[j] = val[j]; } while (i < len) { char c = val[i]; buf[i] = (c == oldChar) ? newChar : c; i++; } // 创建一个新的String对象,原String对象不会发生变化 return new String(buf, true); } } return this; }
public static Long valueOf(long l) { final int offset = 128; if (l >= -128 && l <= 127) { // will cache return LongCache.cache[(int)l + offset]; } return new Long(l); } // 缓存,等价于对象池 private static class LongCache { private LongCache(){} static final Long cache[] = new Long[-(-128) + 127 + 1]; static { for(int i = 0; i < cache.length; i++) cache[i] = new Long(i - 128); } }
基本上所有基础类型的包装类都不适合做锁,因为它们内部用到了享元模式
// al和bl是同一个对象 class A { private Long al = Long.valueOf(1); public void set() { synchronized (al) { } } } class B { private Long bl = Long.valueOf(1); public void set() { synchronized (bl) { } } }
@Data class Foo { private int age = 0; private String name = "abc"; } final class Bar { private final Foo foo = new Foo(); public void setAge(int age) { // 属性foo虽然是final,但依然可以通过setAge修改foo的属性age foo.setAge(age); } }
不可变对象是线程安全的,但并不意味着引用这些不可变对象的对象也是线程安全的
// C 线程安全 @Data final class C { final int age = 0; final String name = "abc"; } // D 线程不安全 class D { private C c; // 在多线程环境下,并不能保证可见性和原子性 // 如果仅需保证可见性,无需保证原子性,可以用volatile修饰c // 如果需要保证原子性,可以通过原子类来实现 public void setC(C c) { this.c = c; } }
转载请注明出处:http://zhongmingmao.me/2019/05/18/java-concurrent-immutability/
访问原文「 Java并发 -- Immutability模式 」获取最佳阅读体验并参与讨论