线程和进程的区别是什么?
关系:min<=active<=max
public class SingletonObject1 {
/**
* can't lazy load
*/
private static final SingletonObject1 instance = new SingletonObject1();
private SingletonObject1() {
}
public static SingletonObject1 getInstance(){
return instance;
}
}
public class SingletonObject2 {
private static SingletonObject2 instance;
private SingletonObject2() {
}
public static SingletonObject2 getInstance() {
if (instance == null) {
instance = new SingletonObject2();
}
return instance;
}
}
public class SingletonObject3 {
private static SingletonObject3 instance;
private SingletonObject3() {
}
public synchronized static SingletonObject3 getInstance() {
if (instance == null) {
instance = new SingletonObject3();
}
return instance;
}
}
- public class SingletonObject4 {
private static SingletonObject4 instance;
private SingletonObject4() {
}
public static SingletonObject4 getInstance() {
if (instance == null) {
synchronized (SingletonObject4.class){
if (instance == null){
instance = new SingletonObject4();
}
}
}
return instance;
}
}
会出现空指针异常的问题,因为虽然成功的保证了单例原则,当其余的线程返回这个对象的时候,该类中的实例域可能还没有初始化完成
public class SingletonObject5 {
private static volatile SingletonObject5 instance;
private SingletonObject5() {
}
public static SingletonObject5 getInstance() {
if (instance == null) {
synchronized (SingletonObject5.class){
if (instance == null){
instance = new SingletonObject5();
}
}
}
return instance;
}
}
public class SingletonObject6 {
private static volatile SingletonObject6 instance;
private SingletonObject6() {
}
private static class InstanceHolder {
private static final SingletonObject6 instance = new SingletonObject6();
}
public static SingletonObject6 getInstance() {
return InstanceHolder.instance;
}
}
public class SingletonObject7 {
private SingletonObject7() {
}
private enum Singleton {
INSTANCE;
private final SingletonObject7 instance;
Singleton() {
instance = new SingletonObject7();
}
public SingletonObject7 getInstance() {
return instance;
}
}
public static SingletonObject7 getInstance() {
return Singleton.INSTANCE.getInstance();
}
public static void main(String[] args) {
Thread[] thread = new Thread[10];
for (int i = 0; i < 10; i++) {
thread[i] = new Thread(() -> {
System.out.println(SingletonObject7.getInstance());
});
thread[i].start();
}
}
}
public class WaitSet {
private static final Object LOCK = new Object();
/**
* 1、所有的对象都会有一个wait set,用来存放调用了该对象wait方法之后进入BLOCK状态的线程
* 2、线程被notify之后,不一定立即得到执行
* 3、线程从wait set中被唤醒顺序不一定是 FIFO
* @param args
*/
public static void main(String[] args) throws InterruptedException {
IntStream.rangeClosed(1, 10).forEach(i -> new Thread(String.valueOf(i)) {
@Override
public void run() {
synchronized (LOCK) {
try {
Optional.of(Thread.currentThread().getName() + " will come to wait set.").ifPresent(System.out::println);
LOCK.wait();
Optional.of(Thread.currentThread().getName() + " will leave to wait set.").ifPresent(System.out::println);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start());
Thread.sleep(3000);
IntStream.rangeClosed(1, 10).forEach(i -> {
synchronized (LOCK) {
LOCK.notify();
}
});
}
}
对基本数据类型的变量读取和赋值是保证了原子性的(long,double在32位的操作系统时可能不能保证原子性)
a =10 ->原子性
b=a->不满足:1.read a; 2.assign b;
c++,c=c+1;->不满足:1.read c; 2.add; 3.assign to c;
使用volatile关键字保证可见性
happens-before relationship
try{
lock.lock();
} catch(Exception e){
lock.u nlock();
}
synchronized(obj){
---1---
}
--unlock--2---
1在2之前
3、并未保证原子性
public class VolatileTest2 {
private static int INIT_VALUE = 0;
private final static int MAX_LIMIT = 50;
public static void main(String[] args) {
new Thread(() -> {
while (INIT_VALUE < MAX_LIMIT) {
System.out.println("T1->" + (++INIT_VALUE));
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "ADDER-1").start();
new Thread(() -> {
while (INIT_VALUE < MAX_LIMIT) {
System.out.println("T2->" + (++INIT_VALUE));
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "ADDER-2").start();
}
}
Volatile关键字
1.保证重排序的不会把后面的之类放到屏障的前面,也不会把前面的放到后面
2.强制对缓存的修改操作立刻写出主内存
3.如果是写操作,它会导致其他CPU中的缓存失效
Volatile的使用场景
用于保存线程私有的数据,不同线程之间看不到彼此的ThreadLocal中保存的数据,始终以当前线程(Thread.currentThread())作为key
模拟ThreadLocal的工作原理
public class ThreadLocalSimulator<T> {
private final Map<Thread, T> storage = new HashMap<>();
public void set(T t) {
synchronized (this) {
Thread key = Thread.currentThread();
storage.put(key, t);
}
}
public T get() {
Thread key = Thread.currentThread();
T value = storage.get(key);
return null == value ? initialValue() : value;
}
private T initialValue() {
return null;
}
}
public class Context {
private String name;
protected String cardId;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setCardId(String cardId) {
this.cardId = cardId;
}
public String getCardId() {
return cardId;
}
}
public class ActionContext {
private static final ThreadLocal<Context> threadLocal = ThreadLocal.withInitial(Context::new);
private static class InnerActionContext {
private static ActionContext actionContext = new ActionContext();
}
public static ActionContext getActionContext() {
return InnerActionContext.actionContext;
}
public Context getContext() {
return threadLocal.get();
}
}
public class ExecutionTask implements Runnable {
private QueryFromDBAction queryAction = new QueryFromDBAction();
private QueryFromHttpAction httpAction = new QueryFromHttpAction();
@Override
public void run() {
queryAction.execute();
httpAction.execute();
Context context = ActionContext.getActionContext().getContext();
System.out.println("The Name is " + context.getName() + " and CardId is " + context.getCardId());
}
}
public class QueryFromDBAction {
public void execute() {
try {
Thread.sleep(1000L);
String name = "Alex" + Thread.currentThread().getName();
ActionContext.getActionContext().getContext().setName(name);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class QueryFromHttpAction {
public void execute() {
Context context = ActionContext.getActionContext().getContext();
String cardId = getCardId(context.getName());
context.setCardId(cardId);
}
private String getCardId(String name) {
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "23456789" + name;
}
}
public class ContextTest {
public static void main(String[] args) {
IntStream.range(0, 100).forEach(i -> {
new Thread(new ExecutionTask()).start();
});
}
}
总结:
定义类加载:加载类的加载器
初始类加载器:委托过程中所设计的类加载器
打破双亲委托机制,重写loadClass方法,改变类加载的顺序
import java.io.*;
/**
* @author LiSheng
* @date 2020/7/1 12:35
*/
public class MyClassLoader extends ClassLoader {
private final static String DEFAULT_DIR = "F:\\app\\classloader1";
private String dir = DEFAULT_DIR;
private String classLoaderName;
public MyClassLoader() {
super();
}
public MyClassLoader(String classLoaderName) {
this.classLoaderName = classLoaderName;
}
public MyClassLoader(String classLoaderName, ClassLoader parent) {
super(parent);
this.classLoaderName = classLoaderName;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String classPath = name.replace(".", "/");
File classFile = new File(dir, classPath + ".class");
if (!classFile.exists()) {
throw new ClassNotFoundException("The class " + name + " not found.");
}
byte[] classBytes = loadClassBytes(classFile);
if (null == classBytes || classBytes.length == 0) {
throw new ClassNotFoundException("load the class " + name + "failed");
}
return this.defineClass(name, classBytes, 0, classBytes.length);
}
//破坏双亲委托机制,重写loadclass方法,改变类加载的顺序
@Override
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException {
Class<?> clazz = null;
if (name.startsWith("java.")) {
try {
ClassLoader system = ClassLoader.getSystemClassLoader();
clazz = system.loadClass(name);
if (clazz != null) {
if (resolve) {
resolveClass(clazz);
return clazz;
}
}
} catch (Exception e) {
//ignore
}
}
try {
clazz = findClass(name);
} catch (Exception e) {
}
if (clazz == null && getParent() != null) {
getParent().loadClass(name);
}
return clazz;
}
private byte[] loadClassBytes(File classFile) {
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
FileInputStream fis = new FileInputStream(classFile)) {
byte[] buffer = new byte[1024];
int len = 0;
while ((len = fis.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
baos.flush();
return baos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
public static String getDefaultDir() {
return DEFAULT_DIR;
}
public String getDir() {
return dir;
}
public String getClassLoaderName() {
return classLoaderName;
}
public void setDir(String dir) {
this.dir = dir;
}
public void setClassLoaderName(String classLoaderName) {
this.classLoaderName = classLoaderName;
}
}
运行时包
类的卸载以及classLoader的卸载