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

时间:2019-03-26 07:21:03

标签: java

多年不使用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。

3 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:1)

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

此外,如果原始值为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!

答案 2 :(得分:0)

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

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