首页 > 编程语言 >Java多线程与静态方法

Java多线程与静态方法

时间:2023-06-13 22:36:36浏览次数:35  
标签:Java int void static StaticAction 静态方法 多线程 public


Java多线程与静态方法

多线程中使用静态方法会发生什么事?也就是说多线程访问同一个类的static静态方法会发生什么事?是否会发生线程安全问题

 

public class Test {
    public static void operation(){
        // ... do something
    }
}

 事实证明只要在静态函数中没有处理多线程共享数据,就不存在着多线程访问同一个静态方法会出现资源冲突的问题。下面看一个例子:

public class StaticThread implements Runnable {
    @Override
    public void run() {
        // TODO Auto-generated method stub
        StaticAction.print();
    }
 
    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(new StaticThread()).start();
        }
    }
}

 

public class StaticAction {
    public static int i = 0;
 
    public static void print() {
        int sum = 0;
        for (int i = 0; i < 10; i++) {
            System.out.print("step " + i + " is running.");
            sum += i;
        }
        if (sum != 45) {
            System.out.println("Thread error!");
            System.exit(0);
        }
        System.out.println("sum is " + sum);
    }
}

 

运行效果图如下:

Java多线程与静态方法_操作系统


 

我们可以看到各个线程对静态方法的访问是交叉执行的,但是这并不影响各个线程静态方法print()中sum值的计算。也就是说,在此过程中没有使用全局变量的静态方法在多线程中是安全的,静态方法是否引起线程安全问题主要看该静态方法是否对全局变量(静态变量static member)进行修改操作

各自实例字段(instance field)的副本,而共享一个静态字段(static field)。所以说,如果该静态方法不去操作一个静态成员,只在方法内部使用实例字段(instance field),不会引起安全性问题。

互斥访问的方式进行安全处理。我们来看一下没有使用互斥访问的话会产生怎样的问题:

public class StaticAction {
    public static int i = 0;
 
    public static void incValue() {
        int temp = StaticAction.i;
        try {
            Thread.sleep(1);
        } catch (Exception e) {
            e.printStackTrace();
        }
        temp++;
        StaticAction.i = temp;
    }
}

 

public class StaticThread implements Runnable {
 
    @Override
    public void run() {
        // TODO Auto-generated method stub
        StaticAction.incValue();
    }
 
    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(new StaticThread()).start();
        }
        try {
            Thread.sleep(1000);    //预留足够的时间让上面的线程跑完
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(StaticAction.i);
    }
}

 

运行结果如下:

Java多线程与静态方法_操作系统_02


 在这里我们就可以看出问题了。为了实现互斥访问,这时我们需要加入一个synchronized关键字。代码修改如下:

public class StaticAction {
    public static int i = 0;
 
    public synchronized static void incValue() {
        int temp = StaticAction.i;
        try {
            Thread.sleep(1);
        } catch (Exception e) {
            e.printStackTrace();
        }
        temp++;
        StaticAction.i = temp;
    }
}

 

public class StaticThread implements Runnable {
 
    @Override
    public void run() {
        // TODO Auto-generated method stub
        StaticAction.incValue();
    }
 
    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(new StaticThread()).start();
        }
        try {
            Thread.sleep(1000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(StaticAction.i);
    }
}

 

运行结果如下,这回不会出现什么问题了:

Java多线程与静态方法_多线程_03


 

加入synchronized关键字的静态方法称为同步静态方法

对象锁其它线程不能进入这个类的任何静态同步方法。它不像实例方法,因为多个线程可以同时访问不同实例同步实例方法。这个其实就是操作系统中的用信号量实现进程的互斥与同步问题,如果涉及在同一个类中有多个静态方法中处理多线程共享数据的话,那就变成用信号量解决生产者-消费者问题。也就是说,静态方法是一份临界资源,对静态方法的访问属于进入临界区;对静态变量的修改是一份临界资源,对静态变量的修改属于进入临界区。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

标签:Java,int,void,static,StaticAction,静态方法,多线程,public
From: https://blog.51cto.com/u_16160131/6473887

相关文章

  • Redis入门 – Jedis存储Java对象 - (Java序列化为byte数组方式)
     Redis入门–Jedis存储Java对象-(Java序列化为byte数组方式) 在Jedis开发中,我们很多时候希望直接把一个对象放到Redis中,然后在需要的时候取出来。Redis的key和value都支持二进制安全的字符串,存储Java对象不是问题,下面我们看一下如何来实现。 1要存储的对象现在写一个很土的J......
  • Java中使用Jedis操作Redis
     Java中使用Jedis操作Redis 请使用jdk1.7版本   Jedis链接池packagecom.stephen.redis;importjava.util.HashMap;importjava.util.List;importjava.util.Map;importcom.stephen.utility.DateTool;importredis.clients.jedis.Jedis;importredis.clients.jedis.......
  • java并发之CAS(Compare and swap)
    1.简介CAS的底层调用native方法,最终是利用CPU的一个特殊指令,该指令由CPU保证了原子性,而且包含多个操作,比如先比较再更新。原理:(1)需要读写的内存值(V)、原值(A)和新值(B)。如果V的值与原值A相匹配,那么把B设置给V,否则处理器不做任何操作。(2)无论哪种情况,都返回V内存值。(3)原子类里,当......
  • Java并发之 Lock 锁
    一、Lock接口1Lock简介&地位&作用锁是一种工具,用于控制对共享资源的访问Lock和synchronized是最常见的两个锁,他们都能够达到线程安全的目录,但是使用和功能上又有较大的不同Lock接口最常见的实现类就是ReentrantLock通常情况下Lock只允许一个线程访问共享资源,特殊情况也允......
  • Java并发之原子类
    一、原子类简介1什么是原子类Java中提供了一些原子类,原子类包装了一个变量,并且提供了一系列对变量进行原子性操作的方法。原子性的意思是对于一组操作,要么全部执行成功,要么全部执行失败,不能只有其中某几个执行成功。在多线程的情况下能够保证操作不会被中断,从而能保证并发安......
  • Java并发工具之ThreadLocal
    一、ThreadLocal简介1.ThreadLocal是什么?ThreadLocal字面意思是本地线程,其实更准确来说是线程局部变量,线程类Thread有个变量叫做threadLocals,其类型就是ThreadLocal.ThreadLocalMap类型,他其实不是一个Map类型,但可以暂时理解它是一个Map,键为ThreadLocal对象,值就是要......
  • Java中Lambda表达式
    Demo1:packagecom.itheima.d9_lambda;publicclassLambdaDemo1{publicstaticvoidmain(String[]args){//目标:学会使用lambda的标准格式简化匿名内部类的代码形式Animala=newAnimal(){@Overridepublicvoidrun(......
  • Java反序列化Commons-Collection篇06-CC5链
    <1>环境分析jdk:jdk8u65CC:Commons-Collections3.2.1pom.xml添加<dependencies><dependency><groupId>commons-collections</groupId><artifactId>commons-collections</artifactId>......
  • Java课程设计--象棋--齐鲁工业大学
    目录1.项目简介2.项目采用技术 3.功能需求分析4.项目亮点5.项目功能架构图和UML类图6.主要功能截图7.团队成员负责模块(表格形式)8.项目git地址9.团队成员git提交截图10.项目总结 正文1.项目简介主要研究基于JAVA技术的中国象棋游戏的分析与设计,对中国象棋游......
  • Java基本查找,二分查找,选择排序
    一、基本查找packagecom.itheima.d8_sort_binarysearch;/***基本查找*/importjava.util.Scanner;publicclassTest3{publicstaticvoidmain(String[]args){//1、定义一个数组(基本查找)int[]arr={12,95,1,3,76,4,2,93,56,49,67};......