繁体   English   中英

有关多线程的Java初学者问题

[英]A Java beginner question regarding multi-threading

多年不使用Java之后,我正在提高自己的Java技能。 最近,我一直在阅读有关多线程的一章,其中提到:

“但是,如果您有一个访问静态字段的非静态方法?或者是访问一个非静态字段(使用实例)的静态方法?在这些情况下,事情很快就会变得混乱起来,如果您有静态方法访问非静态字段,并且同步了该方法,则您将获得对Class对象的锁定,但是如果还有另一个方法也可以访问该对象,该怎么办?非静态字段,这一次使用非静态方法吗?它可能在当前实例(this)上同步请记住,静态同步方法和非静态同步方法不会互相阻塞,它们可以在以下位置运行同时。

为了学习起见,我一直在尝试编写一个示例,其中上面的片段中引用了一种方案:该程序中的静态同步方法修改了一个非静态字段,该方法同时运行一个非静态字段。同步方法。

因此,到目前为止,我还没有成功做到这一点。 感谢您的帮助。 谢谢!

以下是我完成的代码示例。 但是,正如预期的那样,由于线程已同步,因此它们不会同时运行。 我只是想看看书上提到的一个例子,所以我会知道不该做什么。

class code147_class1{
    int num1 = 111;
    static int num2 = 222;

}//code147_class1


public class code147 implements Runnable {

    code147_class1 z = new code147_class1();

    public static void main (String args[]){
        System.out.println("Program has started...");
        System.out.println("The value of the instance variable is:"+new code147_class1().num1);
        System.out.println("The value of the static variable is:"+code147_class1.num2);

        code147 cd1 = new code147();

        Thread thread1 = new Thread(cd1);
        Thread thread2 = new Thread(cd1);

        thread1.start();
        thread2.start();


    }//main

    public void run(){
        System.out.println("Thread has started for:"+Thread.currentThread().getId());

        try{
        subtract_instance_var(z);
        Thread.sleep(100);
        code147.static_subtract_instance_var(z);
        }
        catch(Exception ex){

        }
    }//run

    public synchronized void subtract_instance_var(code147_class1 x){
       if(x.num1 ==111){

           try{
               Thread.sleep(100);
           }
           catch(Exception ex){
           }

           x.num1 = x.num1 - 11;
           System.out.println("Value is subtracted at thread:"+Thread.currentThread().getId());

       }//if

       System.out.println("The value of instance variable at the end for thread: "+Thread.currentThread().getId()+"  is "+x.num1);

    }//subtract_instance_var

    public synchronized static void  static_subtract_instance_var(code147_class1 x){
        if (x.num1==111){
            try{
                Thread.sleep(100);
            }
            catch(InterruptedException ex){
            }//catch
            x.num1 = x.num1 -11;
            System.out.println("Value is subtracted at thread:"+Thread.currentThread().getId());
        }//if

        System.out.println("STATIC The value of instance variable at the end for thread: "+Thread.currentThread().getId()+"  is "+x.num1);

    }//stati_subtract_var

}//class

运行代码后,我期望实例变量的值为89。但是该程序的结果为100。

您得到的结果100是正确的。 线程1和线程2将同时运行。 因为“ subtract_instance_var”方法是同步的,所以一个线程将使变量100。然后该线程将进入睡眠状态。 随着锁释放,其他线程可以执行“ subtract_instance_var”。 但是,由于“ x.num1 == 111”条件失败,将不会发生任何事情。 休眠后,当两个线程都尝试执行“ static_subtract_instance_var”方法时,“ x.num1 == 111”的条件仍然失败。 因此变量值仍为100。

您的示例代码不会同时执行静态减法和实例减法。 因此,没有线程安全。

另外,如果原始值为111,则您的代码仅减去11。因此,结果为100。

这是一个备用的main,它将同时执行substract和static_substract。

public static void main(String args[]) {
        System.out.println("Program has started...");
        System.out.println("The value of the instance variable is:" + new Code147_class1().num1);
        System.out.println("The value of the static variable is:" + Code147_class1.num2);

        Code147 cd1 = new Code147();

        Thread thread1 = new Thread(() -> {
            IntStream.range(0, 5).forEach(i->{
                cd1.subtract_instance_var(cd1.z);
            });
        }, "instance thread");
        Thread thread2 = new Thread(() -> {
            IntStream.range(0, 5).forEach(i->{
                static_subtract_instance_var(cd1.z);
            });
        }, "static thread");

        thread1.start();
        thread2.start();

    }// main

请注意,在此代码中,两个线程从初始111减去每个11,共5次。剩下的应该是1。由于线程安全,它不一定总是这样。

完整代码存在线程安全问题

import java.util.stream.IntStream;

class Code147_class1 {
    int num1 = 111;

}// Code147_OK_class1

public class Code147 {

    Code147_OK_class1 z = new Code147_OK_class1();

    public static void main(String args[]) {
        System.out.println("Program has started...");
        System.out.println("The value of the instance variable is:" + new Code147_OK_class1().num1);

        Code147 cd1 = new Code147();

        Thread thread1 = new Thread(() -> {
            IntStream.range(0, 5).forEach(i -> {
                System.out.println("\tInstance Substract 11 #" + (i + 1));
                cd1.subtract_instance_var(cd1.z);
            });
        }, "instance thread");
        Thread thread2 = new Thread(() -> {
            IntStream.range(0, 5).forEach(i -> {
                System.out.println("\tStatic Substract 11 #" + (i + 1));
                static_subtract_instance_var(cd1.z);
            });
        }, "static thread");

        thread1.start();
        thread2.start();

    }// main

    public synchronized void subtract_instance_var(Code147_OK_class1 x) {
        // if (x.num1 == 111) {

        try {
            Thread.sleep(100);
        } catch (Exception ex) {
        }

        x.num1 = x.num1 - 11;
        System.out.println("Value is subtracted at thread T" + Thread.currentThread().getId());

        // } // if

        System.out.println("The value of instance variable at the end for thread T" + Thread.currentThread().getId()
                + "  is " + x.num1);

    }// subtract_instance_var

    public synchronized static void static_subtract_instance_var(Code147_OK_class1 x) {
        // if (x.num1 == 111) {
        try {
            Thread.sleep(100);
        } catch (InterruptedException ex) {
        } // catch
        x.num1 = x.num1 - 11;
        System.out.println("STATIC Value is subtracted at thread T" + Thread.currentThread().getId());
        // } // if

        System.out.println("STATIC The value of instance variable at the end for thread T"
                + Thread.currentThread().getId() + "  is " + x.num1);

    }// stati_subtract_var

}// class

示例输出

Program has started...
The value of the instance variable is:111
    Instance Substract 11 #1
    Static Substract 11 #1
STATIC Value is subtracted at thread T11
STATIC The value of instance variable at the end for thread T11  is 89
    Static Substract 11 #2
Value is subtracted at thread T10
The value of instance variable at the end for thread T10  is 89
    Instance Substract 11 #2
Value is subtracted at thread T10
STATIC Value is subtracted at thread T11
The value of instance variable at the end for thread T10  is 67
    Instance Substract 11 #3
STATIC The value of instance variable at the end for thread T11  is 67
    Static Substract 11 #3
STATIC Value is subtracted at thread T11
Value is subtracted at thread T10
The value of instance variable at the end for thread T10  is 45
    Instance Substract 11 #4
STATIC The value of instance variable at the end for thread T11  is 45
    Static Substract 11 #4
Value is subtracted at thread T10
STATIC Value is subtracted at thread T11
The value of instance variable at the end for thread T10  is 23
    Instance Substract 11 #5
STATIC The value of instance variable at the end for thread T11  is 23
    Static Substract 11 #5
Value is subtracted at thread T10
The value of instance variable at the end for thread T10  is 12
STATIC Value is subtracted at thread T11
STATIC The value of instance variable at the end for thread T11  is 12

请注意,最后一个值是12,而不是1 ...

固定了线程安全性的完整代码

您可以通过在同一监视器上进行同步来确保程序线程的安全,在本例中为z:

import java.util.stream.IntStream;

class Code147_OK_class1 {
    int num1 = 111;

}// Code147_OK_class1

public class Code148_OK {

    Code147_class1 z = new Code147_class1();

    public static void main(String args[]) {
        System.out.println("Program has started...");
        System.out.println("The value of the instance variable is:" + new Code147_class1().num1);

        Code148_OK cd1 = new Code148_OK();

        Thread thread1 = new Thread(() -> {
            IntStream.range(0, 5).forEach(i -> {
                System.out.println("\tInstance Substract 11 #" + (i + 1));
                cd1.subtract_instance_var(cd1.z);
            });
        }, "instance thread");
        Thread thread2 = new Thread(() -> {
            IntStream.range(0, 5).forEach(i -> {
                System.out.println("\tStatic Substract 11 #" + (i + 1));
                static_subtract_instance_var(cd1.z);
            });
        }, "static thread");

        thread1.start();
        thread2.start();

    }// main

    public /* synchronized */ void subtract_instance_var(Code147_class1 x) {
        synchronized (x) {
            // if (x.num1 == 111) {

            try {
                Thread.sleep(100);
            } catch (Exception ex) {
            }

            x.num1 = x.num1 - 11;
            System.out.println("Value is subtracted at thread T" + Thread.currentThread().getId());

            // } // if

            System.out.println("The value of instance variable at the end for thread T" + Thread.currentThread().getId()
                    + "  is " + x.num1);
        }

    }// subtract_instance_var

    public /* synchronized */ static void static_subtract_instance_var(Code147_class1 x) {
        synchronized (x) {
            // if (x.num1 == 111) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException ex) {
            } // catch
            x.num1 = x.num1 - 11;
            System.out.println("STATIC Value is subtracted at thread T" + Thread.currentThread().getId());
            // } // if

            System.out.println("STATIC The value of instance variable at the end for thread T"
                    + Thread.currentThread().getId() + "  is " + x.num1);
        }

    }// stati_subtract_var

}// class

输出量

Program has started...
The value of the instance variable is:111
    Instance Substract 11 #1
    Static Substract 11 #1
Value is subtracted at thread T10
The value of instance variable at the end for thread T10  is 100
    Instance Substract 11 #2
STATIC Value is subtracted at thread T11
STATIC The value of instance variable at the end for thread T11  is 89
    Static Substract 11 #2
Value is subtracted at thread T10
The value of instance variable at the end for thread T10  is 78
    Instance Substract 11 #3
STATIC Value is subtracted at thread T11
STATIC The value of instance variable at the end for thread T11  is 67
    Static Substract 11 #3
Value is subtracted at thread T10
The value of instance variable at the end for thread T10  is 56
    Instance Substract 11 #4
STATIC Value is subtracted at thread T11
STATIC The value of instance variable at the end for thread T11  is 45
    Static Substract 11 #4
Value is subtracted at thread T10
The value of instance variable at the end for thread T10  is 34
    Instance Substract 11 #5
STATIC Value is subtracted at thread T11
STATIC The value of instance variable at the end for thread T11  is 23
    Static Substract 11 #5
Value is subtracted at thread T10
The value of instance variable at the end for thread T10  is 12
STATIC Value is subtracted at thread T11
STATIC The value of instance variable at the end for thread T11  is 1

告诉我如果Java 8 lambda的东西不清楚,我将用“经典的” Runnables和循环将其重写。

HTH!

通过@Highbrainer的输入,我设法使一个程序运行2个线程,其中1个运行同步实例方法,另一个运行静态方法。 两者都修改实例字段。 正如书中所建议的那样,为避免此类问题,我们应该始终从实例方法修改实例字段,并从as静态方法修改静态字段。 我刚刚修改了程序,将静态方法更改为实例方法。

class code148_class1{
    int num1 = 111;

}//code148_class1


public class code148 implements Runnable {

    static code148_class1 z = new code148_class1();

    public static void main (String args[]){
        System.out.println("Program has started...");
        System.out.println("The value of the instance variable is:"+z.num1);

        code148 cd1 = new code148();

        Thread thread1 = new Thread(
        ()->{
            cd1.subtract_instance_var(z);
        }
        );
        Thread thread2 = new Thread(
                ()->{
                    cd1.NONstatic_subtract_instance_var(z);
                }
        );

        thread1.start();
        thread2.start();


    }//main

    public void run(){
        System.out.println("Thread has started for:"+Thread.currentThread().getId());

//        try{
//        subtract_instance_var(z);
//        Thread.sleep(100);
//        code148.static_subtract_instance_var(z);
//        }
//        catch(Exception ex){
//            
//        }
    }//run

    public synchronized void subtract_instance_var(code148_class1 x){
       if(x.num1 ==111){

           try{
               Thread.sleep(100);
           }
           catch(Exception ex){
           }

           x.num1 = x.num1 - 11;
           System.out.println("Value is subtracted at thread:"+Thread.currentThread().getId());

       }//if

       System.out.println("The value of instance variable at the end for thread: "+Thread.currentThread().getId()+"  is "+x.num1);

    }//subtract_instance_var

    public synchronized void  NONstatic_subtract_instance_var(code148_class1 x){
        if (x.num1==111){
            try{
                Thread.sleep(100);
            }
            catch(InterruptedException ex){
            }//catch
            x.num1 = x.num1 -11;
            System.out.println("Value is subtracted at thread:"+Thread.currentThread().getId());
        }//if

        System.out.println("STATIC The value of instance variable at the end for thread: "+Thread.currentThread().getId()+"  is "+x.num1);

    }//stati_subtract_var

}//class

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM