多线程:synchronized代码块、synchronized方法、静态synchronized方法使用的锁

在学习多线程的过程中,很多资料都会指出synchronized代码块和synchronized方法使用的锁都是this ,静态synchronized方法使用的锁是类锁,那么从这个结论出发,如何进行逆向证明呢?

证明this锁

``

public class ThreadDemo3 {    public static void main(String[] args) throws InterruptedException{        MyThread3 mt = new MyThread3();        Thread t1 = new Thread(mt, "窗口1");        Thread t2 = new Thread(mt, "窗口2");        t1.start();        Thread.sleep(40);        mt.flag = false;        t2.start();    }}?class MyThread3 implements Runnable {    int tickets = 100;    boolean flag = true;    Object obj = new Object();?    public void run() {        if (flag) {            while (tickets > 0) {                synchronized (obj) {                    if (tickets > 0) {                        try {                            Thread.sleep(40);                        } catch (InterruptedException e) {                            e.printStackTrace();                        }                        System.out.println(Thread.currentThread().getName() + "售出了" + (100 - tickets + 1) + "张票");                        tickets--;                    }                }            }        } else {            while (tickets > 0) {                sell();            }        }    }?    synchronized public void sell() {        if (tickets > 0) {            try {                Thread.sleep(40);            } catch (InterruptedException e) {                e.printStackTrace();            }            System.out.println(Thread.currentThread().getName() + "售出了" + (100 - tickets + 1) +"张票");            tickets--;        }    }}

代码如上,简单说明下思路,synchronized同步代码块用obj作为锁的时候,打印的结果:两个线程随机打印,从第1张票卖到101张,说明出现了线程不安全问题,从而可以得出线程t1和t2没有同步执行的结论;

再把同步代码块中的锁改成this对象,再次执行,打印的结果为:两个线程随机打印,从第1张票卖到100张。

证明类锁

把上面的代码再稍作修改,将sell方法,flag对象,tickets对象加上static修饰符,再次运行代码,可以看到结果又打印了101张票,说明静态方法使用的并非this锁,我们根据结论,把synchronized同步代码块里的锁换成"MyThread3.class"再运行程序,同步现象出现!

这样一来就可以验证开头的结论了

做个小总结,在写这段代码的过程中,犯了一个问题,把while循环写到了synchronized代码块中,这样做会导致线程同步以后,变成单线程执行,线程t2永远不会获得执行的机会!!所以一定要注意在多线程编码过程中,同步代码块的范围

 

原文地址:https://www.cnblogs.com/blogforvi/p/12164225.html

时间: 2024-08-27 14:02:50

多线程:synchronized代码块、synchronized方法、静态synchronized方法使用的锁的相关文章

JAVA之旅(十三)——线程的安全性,synchronized关键字,多线程同步代码块,同步函数,同步函数的锁是this

JAVA之旅(十三)--线程的安全性,synchronized关键字,多线程同步代码块,同步函数,同步函数的锁是this 我们继续上个篇幅接着讲线程的知识点 一.线程的安全性 当我们开启四个窗口(线程)把票陆陆续续的卖完了之后,我们要反思一下,这里面有没有安全隐患呢?在实际情况中,这种事情我们是必须要去考虑安全问题的,那我们模拟一下错误 package com.lgl.hellojava; import javax.security.auth.callback.TextInputCallback

从头认识多线程-2.12 synchronized ()代码块不单可以用this,也可以用其他对象

这一章节我们来讨论一下synchronized ()代码块的另一个用法,它不单可以用this,也可以用其他对象. 1.代码清单 package com.ray.deepintothread.ch02.topic_13; /** * * @author RayLee * */ public class ObjectLock { public static void main(String[] args) throws InterruptedException { MyService myServi

java 成员变量、局部变量、静态变量、类变量、非静态变量、实例变量、向前引用、非法向前引用、静态代码块、非静态代码块

①java类的成员变量有俩种: 一种是被static关键字修饰的变量,叫类变量或者静态变量 另一种没有static修饰,为成员变量 ②通俗点说: 类的静态变量在内存中只有一个,java虚拟机在加载类的过程中为静态变量分配内存,静态变量位于方法区,被类的所有实例共享.静态变量可以直接通过类名进行访问,其生命周期取决于类的生命周期. 而实例变量取决于类的实例.每创建一个实例,java虚拟机就会为实例变量分配一次内存,实例变量位于堆区中,其生命周期取决于实例的生命周期. 注意点: 1.JAVA中初始化

static{}(静态代码块)与{}(非静态代码块)的异同点(转自 べ袽猓柯苡づ)

static{}(静态代码块)与{}(非静态代码块)的异同点 相同点:都是在JVM加载类时且在构造方法执行之前执行,在类中都可以定义多个, 一般在代码块中对一些static变量进行赋值. 不同点:静态代码块在非静态代码块之前执行(静态代码块->非静态代码块->构造方法). 静态代码块只在第一次new执行一次,之后不再执行,而非静态代码块在每new 一次就执行一次.非静态代码块可在普通方法中定义(不过作用不大):而静态代码块不行. 例: //普通类 publicclass PuTong {   

Java静态代码块和非静态代码块、类加载、构造对象的机制

温故而知新,代码块这东西时间一长一些东西容易忘记,比如静态代码块.非静态代码款.静态成员变量初始化.动态成员变量初始化.构造方法调用.类加载等等的顺序机制是怎么样的? 话不多说了,一个例子足以说明一切: package com.collectiontest; import org.junit.Test; public class BasicTest { @Test public void testBlock() { System.out.println("m1:"); Mimi m1=

静态代码块、非静态代码块(普通代码块)和构造方法的执行顺序

Java中经常有一些静态块,这是用来在生成类之前进行的初始化,无论java还C++语言中的static,都是最先初始化好的.结构如下: static { 静态语句代码块 } { 非静态语句代码块 }  相同点:都是在JVM加载类时且在构造方法执行之前执行,在类中都可以定义多个,一般在代码块中对一些static变量进行赋值. 不同点:静态代码块在非静态代码块之前执行(静态代码块-->非静态代码块-->构造函数). 1 public class Test_Static_Class { 2 //静态

静态代码块、非静态代码块、构造函数之间的执行顺序

1.执行顺序 静态代码块>非静态代码块>构造函数 public class staticCode { public staticCode() { System.err.println("构造函数"); } { System.err.println("非静态代码块"); } static{ System.err.println("静态代码块"); } public static void main(String[] args) { ne

静态代码块、非静态代码块、构造方法的执行顺序

java中经常有一些静态块,这是用来在生成类之前进行的初始化,无论java还C++语言中的static,都是最先初始化好的.结构如下: static { 静态语句代码块 } { 非静态语句代码块 } 异同点 相同点:都是在JVM加载类时且在构造方法执行之前执行,在类中都可以定义多个,一般在代码块中对一些static变量进行赋     值. 不同点:静态代码块在非静态代码块之前执行(静态代码块-->非静态代码块-->构造方法).     静态代码块只在第一次new执行一次,之后不在执行,而非静态

静态代码块与非静态代码块

非静态代码块: 1.可以有输出语句 2.可以对类的属性.类的声明进行初始化 3.可以调用静态的变量或方法 4.如果有多个非静态代码块,按从上到下顺序执行 5.每次创建对象时,都会执行一次,且优先于构造器执行 静态代码块: 1.可以有输出语句 2.可以对类的属性.类的声明进行初始化 3.不可以调用非静态的变量或方法 4.若有多个静态代码块,按从上到下的顺序执行 5.静态代码块的执行优先于非静态代码块 6.静态代码块只执行一次 原文地址:https://www.cnblogs.com/keleaiw