首页 > 编程语言 >Java多线程(2):线程关键字

Java多线程(2):线程关键字

时间:2022-10-23 08:22:16浏览次数:54  
标签:Java synchronized void flag 线程 volatile 多线程 public

您好,我是湘王,这是我的博客园,欢迎您来,欢迎您再来~

 

Java中和线程相关的关键字就两:volatile和synchronized。

volatile以前用得较少,以后会用得更少(后面解释)。它是一种非常轻量级的同步机制,它的三大特性是:

1、保证可见性,即强制将CPU高速缓存的数据立即写入主存,会导致其他CPU核中对应的高速缓存内容无效,就像这样:

 

 

 

如果由于同步需要,某行代码使用了volatile关键字,那么当CPU内核1收到指令时,会立即将它位于高速缓存中的数据(这里是字符串“1”)写到主存中去,那么其余的数据(“哈哈”、“test”、9.9)会全部失效。

 

2、有序性(禁止指令重排)

所谓指令重排,就是对于int a = 0、 int b = 1这类赋值语句,编译成class字节码时,a = 0,b = 1的顺序可能会因为编译器的优化而导致和书写时的顺序不一致。但如果有c = a + b,那么这行代码必须在前两句的后面执行。这个不用深究,知道就好了。

3、不保证原子性

所谓不保证原子性,就是如果遇到多个线程同时执行i = i + 1,那么i可能就不能保证仅仅被加1了。

 

根据Java的内存模型整理出如下这些规则,看看就好,能理解就记住,理解不了也没关系,不用记:

 

 

 

下面还是以代码来说明:

public class VolatileTest extends Thread {
    static boolean flag = true;

    @Override
    public void run() {
        while (flag) {
        }
        System.out.println("子线程结束");
    }

    public static void main(String[] args) throws InterruptedException {
        new Thread(new VolatileTest()).start();
        TimeUnit.SECONDS.sleep(1);
        flag = false;
        System.out.println("主线程结束");
    }
}

 

 

加上volatile之后,子线程就不会一直卡住了:

public class VolatileTest2 extends Thread {
    volatile static boolean flag = true;

    @Override
    public void run() {
        while (flag) {
        }
        System.out.println("子线程结束");
    }

    public static void main(String[] args) throws InterruptedException {
        new Thread(new VolatileTest2()).start();
        TimeUnit.SECONDS.sleep(1);
        flag = false;
        System.out.println("主线程结束");
    }
}

 

 

其实在第一个类VolatileTest中,即使不用volatile关键字,也能让程序正常结束,只需要添加一行代码就行了:

public class VolatileTest3 extends Thread {
    static boolean flag = true;

    @Override
    public void run() {
        while (flag) {
            // 只要在这里随便加一行代码,虽然原理不同,但效果和加了volatile一样
            System.out.println(" ");
        }
        System.out.println("子线程结束");
    }

    public static void main(String[] args) throws InterruptedException {
        new Thread(new VolatileTest3()).start();
        TimeUnit.SECONDS.sleep(1);
        flag = false;
        System.out.println("主线程结束");
    }
}

 

 

所以,总结一下,适应volatile的条件:

1、对变量的写操作不依赖于当前值,就是不会出现 x++ 或 x = x + y 这样的自增性质的语句;

2、变量没有包含在具有其他变量的代码中,就是不会出现 if(x > y) { // dosomething; } 这样的语句,因为这样的话,dosomething就不是线程安全的。

所以适合使用volatile的场景是:

1、状态标记量

2、双重检查

 

状态标记量:只设置简单的状态值,希望立即看到,且无其他变量参与。之前Volatile2中的flag就是这样的状态标记量。

双重检查(这个有点生僻冷门,不深究)。

因为目前synchronized的性能已经有了大幅提升,而且机器硬件的性能也较之前翻了几十倍,volatile存在的意义已经不大了。所以如果对volatile的理解不够深入,就干脆不用理解了。

 

再来看另一个重量级选手:synchronized

synchronized关键字用于解决多个线程之间的资源共享问题,通常有三大作用域:

1、静态方法:public synchronized static void methodName(),进入方法前要获得当前类对象的锁;

2、实例方法:public synchronized void methodName(),进入方法前要获得当前对象实例的锁;

3、代码块:最常用,指定一个特别的加锁对象,进入同步代码块前要获得这个对象锁。

这几个就不一个个地说了,因为网上这类例子太多了。

就简单说一下volatile和synchronized的比较:

1、volatile是synchronized的轻量级实现,性能要比synchronized要好;

2、volatile只能修饰变量,synchronized只能修饰方法和代码块;

3、volatile不会造成阻塞,synchronized会。

 

最后再说一个我之前遇到的小问题:

如果使用的IDE是Eclipse,那么当前活动的线程数量可能是1;

但如果使用的IDE是IDEA,那么当前活动的线程数量可能是2;

有图为证:

 

 

 

这是因为在IDEA中多了一个Monitor Ctrl-Break。

 

 

 

至于这是个啥玩意,各位一查便知。

 

 


 

 

感谢您的大驾光临!咨询技术、产品、运营和管理相关问题,请关注后留言。欢迎骚扰,不胜荣幸~

 

标签:Java,synchronized,void,flag,线程,volatile,多线程,public
From: https://www.cnblogs.com/xiangwang1111/p/16817638.html

相关文章

  • java线程例题-类/对象/实例化/声明/多线程/同步
    packageA_ShangGuiGu.Thread.ThreadTest;importjava.util.concurrent.locks.ReentrantLock;////////////////////////////classzhanghu{//账户类,定义一个余额属性。......
  • 使用lock的方法解决线程同步的安全问题
    packageA_ShangGuiGu.Thread.ThreadTest;importjava.util.concurrent.locks.ReentrantLock;/***解决线程安全问题的方式三:Lock锁-----jdk5.0新增*1.首先要创建一个Re......
  • Java死锁演示和原理
    packageA_ShangGuiGu.Thread.ThreadTest;/***演示死锁问题*1.死锁的理解:不同的线程分别占用对方需要的同步资源,都在等待对方释放自己所需的另一个资源,就形成了死锁。......
  • 同步方法解决线程安全问题
    使用同步方法解决线程安全问题实现接口的同步方法实例packageA_ShangGuiGu.Thread.ThreadDemo;​/***使用同步方法解决Runnable接口的线程安全问题。*将需要对代码......
  • 郁金香 -多线程创建
    #include<stdio.h>#include<Windows.h>//创建线程函数//开辟线程//BUG解决让这两个线程可以长期存在免得无法观察DWORDWINAPI线程函数1(LPVOIDarg){whil......
  • JavaScript 实现 -- 冒泡排序
    冒泡排序冒泡排序(BubbleSort)也叫气泡排序、泡沫排序,是一种比较简单的排序算法。它通过遍历数组,比较相邻的两个元素,如果前一个元素比后一个元素大,则交换它们的位置,这样第......
  • JavaScript 实现 -- 选择排序
    选择排序选择排序是一种简单直观的排序算法。原理第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元......
  • JavaScript 实现 -- 希尔排序
    希尔排序希尔排序是插入排序的一种,又称“缩小增量排序”(DiminishingIncrementSort),是插入排序的一种更高效的改进版本。希尔排序实际上就是分组的插入排序,希尔排序以步长......
  • Java关键字(四)——final
    对于Java中的final关键字,我们首先可以从字面意思上去理解,百度翻译显示如下:也就是说final英文意思表示是最后的,不可更改的。那么对应在Java中也是表达这样......
  • java 类与对象
    1.在定义变量时,java要求必须显示初始化变量。比如以下代码无法通过编译:publicclassTwst{publicstaticvoidmain(String[]wrgs){intvalue;System.out.println(......