进程:一个程序运行起来放入内存中
进程是静态的,一个程序为它分配资源的基本单位
线程是动态的,是执行cpu调度的基本单位
cpu:给我什么指令执行什么指令(会有线程之间的切换,要记录线程执行的程度)
PC
ALU:计算(1+2)
Register:程序计数器
单核cpu为什么有必要考虑多线程
未必所有时间都在做计算(如果一半时间在等待,如果这时间别人不能用就浪费了cpu的资源)
线程池核心线程数设置多少合适
充分利用cpu,一半计算一半等待(2个线程合适)
8核cpu,只有1/4的时间在计算
8480%
4核8线程就是1个ALU 服务2个寄存器
缓存一致性协议(inter 用的是 MESI,不同cpu用的不同的协议)
import java.util.concurrent.CountDownLatch;
public class CacheLinePadding {
public static long COUNT = 1000000000L;
private static class T {
//观察打开前打开后
//private long p1, p2, p3,p4, p5, p6, p7;
public long x = 0L; //8bytes
//private Long p9,p10, p11, p12, p13, p14, p15;
}
public static T[] arr = new T[2];
static {
arr[0] = new T();
arr[1] = new T();
}
public static void main(String[] args) throws Exception {
CountDownLatch latch = new CountDownLatch(2);
Thread t1 = new Thread(() -> {
for (long i = 0; i < COUNT; i++) {
arr[0].x = i;
}
latch.countDown();
});
Thread t2 = new Thread(() -> {
for (long i = 0; i < COUNT; i++) {
arr[1].x = i;
}
latch.countDown();
});
final long start = System.nanoTime();
t1.start();
t2.start();
latch.await();
System.out.println((System.nanoTime() - start) / 1000000);
}
}
cpu乱序
import java.util.concurrent.CountDownLatch;
public class Disorder {
private static int x = 0, y = 0;
private static int a = 0, b = 0;
public static void main(String[] args) throws InterruptedException {
for (long i = 0; i < Long.MAX_VALUE; i++) {
x = 0;
y = 0;
a = 0;
b = 0;
CountDownLatch latch = new CountDownLatch(2);
Thread one = new Thread(new Runnable() {
public void run() {
a = 1;
x = b;
latch.countDown();
}
});
Thread other = new Thread(new Runnable() {
public void run() {
b = 1;
y = a;
latch.countDown();
}
});
one.start();
other.start();
latch.await();
String result = "第" + i + "次(" + x + "," + y + ")";
if (x == 0 && y == 0) {
System.err.println(result);
break;
}
}
}
}
第426291次(0,0)
public class NoVisibility {
private static boolean ready = false;
private static int number;
private static class ReaderThread extends Thread {
@Override
public void run() {
while (!ready) {
Thread.yield();
}
System.out.println(number);
}
}
public static void main(String[] args) throws Exception {
Thread t = new ReaderThread();
t.start();
number = 42;
ready = true;
t.join();
}
}
new 在内存中分配一块内存空间
dup即英文duplicate的缩写,重复的意思,用来定义重复的字节
特殊方法 m=8
astore_1 t关联内存中的值
return
关于Object o = new Object(); 1.请解释一下对象的创建过程? (半初始化) 2.加问DCL要不要加volatile问题? (指令重排) 3.对象在内存中的存储布局?(对象与数组的存储不同) 4.对象头具体包括什么? (markword klas spointer) synchronized锁信息 5.对象怎么定位? (直接间接) 6.对象怎么分配? (栈上-线程本地- Eden-0ld) 7. Object o= new Object()在内存中占用多少字节? 8。新问题:为什么hotspot不使用c++上对象来代表java对象? 9.新问题: Class对象是在堆还是在方法区?
public class Mgr05 {
private static Mgr05 INSTANCE;
private Mgr05() {
}
public static Mgr05 getInstance() {
if (INSTANCE == null) {
//妄图通过减小同步代码块的方式提高效率,然后不可行
synchronized (Mgr05.class) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new Mgr05();
}
}
return INSTANCE;
}
public void m() {
System.out.println("m");
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(() -> {
System.out.println(Mgr05.getInstance().hashCode());
}).start();
}
}
}
因为涉及对象的半初始化所以需要加volatile关键字
public class Mgr06 {
private static volatile Mgr06 INSTANCE;
private Mgr06() {
}
public static Mgr06 getInstance() {
//这个if只是为了避免抢锁提高效率
if (INSTANCE == null) {
synchronized (Mgr06.class) {
if (INSTANCE == null) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new Mgr06();
}
}
}
return INSTANCE;
}
public void m() {
System.out.println("m");
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(() -> {
System.out.println(Mgr06.getInstance().hashCode());
}).start();
}
}
}
double check lock(DCL)
单线程保证结果最终一致性就可以乱序
原子性,有序性,可见性
volatile本质
双重检测机制单例代码:
public class Singleton {
private static volatile Singleton singleton;
private Singleton() {}
public static Singleton getInstance() {
if (singleton == null) { 1
synchronized (Singleton.class) {
if (singleton == null) { 2
singleton = new Singleton(); 3
}
}
}
return singleton;
}
}
了解这个机制之前我们要知道一个定义指令重排:简单理解就是,虚拟机或者CPU会在不影响代码执行结果的情况下,改变代码的执行顺序来优化代码(单线程或正常同步情况下)
singleton = new Singleton()创建对象的过程不是原子性的分为三步:
①.分配对象的内存空间
②.初始化对象
③.将实例指向刚分配的内存地址
但在实际的情况因为指令重排 执行的顺序可能不是①》②》③,而是①》③》②
这就有可能会出现一个问题 : 线程A进入执行代码执行创建代码时执行了①》③时,线程B进入执行代码因为③已经执行了,singleton已经有了内存地址不是null了,所以if不成立直接返回singleton对象,但是由于还没有②初始化对象就会出现错误
为了解决这个问题要使用volatile
volatile主要有两个作用:①可见性 ②有序性
有序性顾名思义用来保证代码顺序执行,告诉虚拟机和CPU这段代码你必须按照顺序执行,不需要你优化。
这样就保证了创建对象必须按照①》②》③来执行,就不会再出现上述的问题了



