什么是内存模型??
public class Thread_Wait_Notify_02 implements Runnable{
private String name;
private Object pre;
private Object self;
private Object ne;
public Thread_Wait_Notify_02(String name, Object pre, Object self,Object ne) {
this.name = name;
this.pre = pre;
this.self = self;
this.ne =ne;
}
@Override
public void run() {
int count=10;
while (count>0){
synchronized (pre){
synchronized (self){
System.out.print(name);
count--;
//System.out.print(self);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
self.notify();
}
try {
pre.wait();
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
synchronized (self){
self.notify();
}
}
}
public class main {
public static void main(String[] strings) throws InterruptedException {
Object a=new Object();
Object b=new Object();
Object c=new Object();
new Thread(){
@Override
public void run(){
}
};//不启动
Thread_Wait_Notify_ pa=new Thread_Wait_Notify_("A",c,a,b);
Thread_Wait_Notify_ pb=new Thread_Wait_Notify_("B",a,b,c);
Thread_Wait_Notify_ pc=new Thread_Wait_Notify_("C",b,c,a);
new Thread(pa,"A").start();
Thread.sleep(1000*2);//确保按ABC这个顺序执行
new Thread(pb,"B").start();
//Thread.sleep(100);
new Thread(pc,"C").start();
// Thread.sleep(100);
//System.out.println(c);
//Thread_Wait_Notify_02 thread_wait_notify_02=new Thread_Wait_Notify_02("B",a,b,c);
//new Thread(thread_wait_notify_02,"第二种实体对象线程").start();
}
}
看输出::
Ajava.lang.Object@75c85cajava.lang.Object@99b6b51java.lang.Object@da4eeba
Bjava.lang.Object@99b6b51java.lang.Object@da4eebajava.lang.Object@75c85ca
Cjava.lang.Object@da4eebajava.lang.Object@75c85cajava.lang.Object@99b6b51
Ajava.lang.Object@75c85cajava.lang.Object@99b6b51java.lang.Object@da4eeba
Bjava.lang.Object@99b6b51java.lang.Object@da4eebajava.lang.Object@75c85ca
Cjava.lang.Object@da4eebajava.lang.Object@75c85cajava.lang.Object@99b6b51
Ajava.lang.Object@75c85cajava.lang.Object@99b6b51java.lang.Object@da4eeba
Bjava.lang.Object@99b6b51java.lang.Object@da4eebajava.lang.Object@75c85ca
Cjava.lang.Object@da4eebajava.lang.Object@75c85cajava.lang.Object@99b6b51
Ajava.lang.Object@75c85cajava.lang.Object@99b6b51java.lang.Object@da4eeba
Bjava.lang.Object@99b6b51java.lang.Object@da4eebajava.lang.Object@75c85ca
Cjava.lang.Object@da4eebajava.lang.Object@75c85cajava.lang.Object@99b6b51
Ajava.lang.Object@75c85cajava.lang.Object@99b6b51java.lang.Object@da4eeba
Bjava.lang.Object@99b6b51java.lang.Object@da4eebajava.lang.Object@75c85ca
Cjava.lang.Object@da4eebajava.lang.Object@75c85cajava.lang.Object@99b6b51
Ajava.lang.Object@75c85cajava.lang.Object@99b6b51java.lang.Object@da4eeba
Bjava.lang.Object@99b6b51java.lang.Object@da4eebajava.lang.Object@75c85ca
Cjava.lang.Object@da4eebajava.lang.Object@75c85cajava.lang.Object@99b6b51
Ajava.lang.Object@75c85cajava.lang.Object@99b6b51java.lang.Object@da4eeba
Bjava.lang.Object@99b6b51java.lang.Object@da4eebajava.lang.Object@75c85ca
Cjava.lang.Object@da4eebajava.lang.Object@75c85cajava.lang.Object@99b6b51
Ajava.lang.Object@75c85cajava.lang.Object@99b6b51java.lang.Object@da4eeba
Bjava.lang.Object@99b6b51java.lang.Object@da4eebajava.lang.Object@75c85ca
Cjava.lang.Object@da4eebajava.lang.Object@75c85cajava.lang.Object@99b6b51
Ajava.lang.Object@75c85cajava.lang.Object@99b6b51java.lang.Object@da4eeba
Bjava.lang.Object@99b6b51java.lang.Object@da4eebajava.lang.Object@75c85ca
Cjava.lang.Object@da4eebajava.lang.Object@75c85cajava.lang.Object@99b6b51
Ajava.lang.Object@75c85cajava.lang.Object@99b6b51java.lang.Object@da4eeba
Bjava.lang.Object@99b6b51java.lang.Object@da4eebajava.lang.Object@75c85ca
Cjava.lang.Object@da4eebajava.lang.Object@75c85cajava.lang.Object@99b6b51
我的理解:结合深入理解jvm书中P363~P365中的内容
每一个线程的栈帧在编译的时候就已经确定,也就是说这个线程内有多少个变量都是确定了的,上面的代码就是Thread_Wait_Notify_02和Thread_Wait_Notify_这两个类的成员属性都是一个线程的栈变量,main线程里面的的new Thread_Wait_Notify_(“A”,c,a,b),就会在内存里面新建一个线程,“A”,c,a,b,是在主线程传给这个线程的数据,“A”在方法区里面,c,a,b传入的是Java堆上的对象本身,也就是Java内存模型上的主内存。
main线程里面.start()后线程就开始运行了每一个用户线程必须有一条线程启动他),main线程的调用线程工作完成,例如上面的代码的A线程进入自己的run()方法执行,synchronized (self)这句话意思很重要:self本身也就是在java堆上的也就是内存模型所说的主内存,A线程会给这个“本身”lock(见JVM书中P364)加锁,read->load->复制副本到自己的线程的工作内存里面,这个时候其他的线程不能访问这个主内存的“本身”。
锁着了主内存的一个“本身之后”,接着按照上面的代码,System.out.print(name);这句话输出了方法区里面的值“A”(name是这个线程栈帧上的变量,指向方法区的“A”)。self.notify(),这句话的涵义:如果主内存里面原来有因为self指向的“本身”而进入等待状态的线程唤醒了(注意注意!!!!这个时候被唤醒的的线程不会立刻往下执行,而是处于一个锁池状态,因为唤醒他的线程的synchronized{}代码块还没结束,只有synchronized结束了唤醒线程才能往下执行)。见下图:
接着往下解析A线程, pre.wait();这句话也超级重要!!!!!!前面已经有了 synchronized (pre)把主内存上的pre的本身已经锁住了,执行了pre.wait();后会释放掉A线程上自己从主内存上锁住的所有“本身”,同时同时,自身(A线程)进入等待状态,也就是相当于这个线程不往下执行了,停在了那里,等待拯救它的线程执行这个pre指向的在主内存的“本身”执行.notify()语句,这样子才会A线程唤醒继续往下面执行。到此为止,A线程成功执行了while循环里面的第一个循环,输出了第一次,自己在等待它的救世主!!!!
这时回到main主线程,这个线程继续new出一个线程B线程,并且.start(),同理,C线程也是如此。每一条线程都是按上述的重复着,一直在解析Thread_Wait_Notify_这个类,Main主线程都是用这个类来新建线程调用线程。3个子线程在在总体上是交替执行的,每一个时刻只有一条线程在执行,另外两条是在等待状态,所以实现了ABCABC…循环输出,在总体上就实现了同步完成了这个功能,三个子线程各司其职,A线程只负责打印A,B线程只负责打印B,C线程只打印C。。。
体会一下没有加锁输出
我们提了这么多锁都是在线程之间传递的数据上加锁,在内存模型上就是主内存上的线程共享的”本身“,比如上面main线程声明的变量a,b,c指向的java堆”本身“。比如在MyThread02的成员变量属性或者在run()方法内声明的变量指向的java堆”本身“,没有涉及到传到其他线程上就没必要加锁。
没有加锁:在语言层面就是没有加synchronized关键字,在内存模型中就是在线程复制主内存时没有进行lock()操作,这个时候对线程来说就是竞争了,竞争的结果是未知的,随机的,完全由cpu来决定。看下面的代码:
解析:Runnable接口内的run()方法如果没有加上synchronized那就是没有给方法的参数指向的”本身“加锁,main主线程启动了两个子线程, String obj=new String(“主线程变量”);//"主线程的变量"分别传给了两个子线程,如果两个线程都没有加锁的话那就是看竞争状态了,随机的,看输出就知道,每一次输出都不一样,完全看cpu的状态。。。加了synchronized后,是线程1先加的锁那就要等线程一先执行完了再到线程2加锁。。所以输出是有序的。
public class MyThread02 implements Runnable {
public MyThread02(String name) {
this.name = name;
}
private String name;
@Override
public void run() {
for (int i=0;i<3;i++){
System.out.println(name+i);
}
}
}
public class main02 {
public static void main(String[] arg){
/*Thread thread = new Thread(new MyThread02("C"));
Thread thread01= new Thread(new MyThread02("D"));
Thread.start()报错
*/
String obj=new String("主线程变量");//"主线程的变量";
String name="hah";
/*synchronized (name){
}*/
new Thread(new MyThread02(obj+"+1")).start();
new Thread(new MyThread02(obj+"+2")).start();
//System.out.println( new Thread());
}
}
run()方法没有加synchronized的输出:
主线程变量+10
主线程变量+20
主线程变量+11
主线程变量+21
主线程变量+22
主线程变量+12
run()方法加了synchronized的输出:
主线程变量+10
主线程变量+11
主线程变量+12
主线程变量+20
主线程变量+21
主线程变量+22
转载:https://blog.csdn.net/weixin_42765975/article/details/102484091