“ Java多线程编程的核心技术(第二版)” -1.2

电脑杂谈  发布时间:2020-07-03 01:12:50  来源:网络整理

多线程技术问题解决_webservice 线程问题_怎么解决线程安全问题

定制线程类中的实例变量可以与其他线程共享或不共享. 这是在多个线程之间进行交互时的重要技术要点.

1. 不共享数据时

未共享数据的情况如图1-18所示.

图1-18未共享数据

让我们看一个不共享数据的示例.

创建一个用于实验的Java项目t3,MyThread.java类代码如下:

公共类MyThread扩展了线程{

private int count = 5;

public MyThread(String name){

super();

this.setName(name); //设置线程名称

}

@Override

public void run(){

super.run();

同时(计数> 0){

count-;

System.out.println(“您” + this.currentThread(). getName()

+“计算,计数=” +计数);

怎么解决线程安全问题_webservice 线程问题_多线程技术问题解决

}

}

}

Run.java的代码如下:

公共类运行{

public static void main(String [] args){

MyThread a = new MyThread(“ A”);

MyThread b = new MyThread(“ B”);

MyThread c = new MyThread(“ C”);

a.start();

b.start();

c.start();

}

}

程序运行的结果如图1-19所示.

从图1-19中可以看到,该程序总共创建了3个线程,每个线程都有自己的计数变量,并减少了自己的计数变量的值. 在这种情况下,变量不会共享. 此示例在任何情况下都不会有多个线程访问同一个实例变量.

如果要实现三个线程对一个count变量执行减法运算,应如何设计代码?

2. 数据共享情况

数据共享情况如图1-20所示.

多线程技术问题解决_webservice 线程问题_怎么解决线程安全问题

对于共享数据,多个线程可以访问相同的变量. 例如,在实现投票功能的软件中,多个线程同时处理同一个人的投票.

让我们看一个共享数据的例子.

创建t4测试项目,MyThread.java类代码如下:

公共类MyThread扩展了线程{

private int count = 5;

@Override

public void run(){

super.run();

count-;

//在此示例中,请勿使用while语句,否则将导致其他线程无法运行

//因为第一个线程执行while语句会将计数值减小为0

//减法总是由一个线程执行

System.out.println(“由“ + this.currentThread(). getName()+”计算,count =” + count);

}

}

Run.java的代码如下:

公共类运行{

public static void main(String [] args){

MyThread mythread = new MyThread();

Thread a = new Thread(mythread,“ A”);

怎么解决线程安全问题_webservice 线程问题_多线程技术问题解决

线程b =新线程(mythread,“ B”);

Thread c = new Thread(mythread,“ C”);

线程d =新线程(mythread,“ D”);

线程e =新线程(mythread,“ E”);

a.start();

b.start();

c.start();

d.start();

e.start();

}

}

程序运行的结果如图1-21所示.

从图1-21中可以看到,线程A和B输出的计数值均为3,表明A和B同时处理计数,从而产生了``非线程安全性''问题. 但是我们要获得输出的结果不会重复,应该依次减小.

发生非线程安全的情况是因为在某些JVM中,count--的操作需要分解为以下三个步骤(执行这三个步骤的过程将被其他线程中断):

1)获取原始计数值.

2)计算count-1.

3)分配要计数的值.

在这三个步骤中,如果同时有多个线程正在访问,则很可能出现非线程安全问题. 获取重复值的步骤如图1-22所示.

A线程和B线程将计数减1以获得相同的4的过程如下.

webservice 线程问题_怎么解决线程安全问题_多线程技术问题解决

1)以1为时间单位,A线程获得计数变量5的值.

2)B线程以2为时间单位获得计数变量5的值.

3)A线程以3为时间单位执行计数计算,并将计算出的值4存储在临时变量中.

4)B线程以4为时间单位执行计数计算,并将计算出的值4存储在临时变量中.

5)在时间单位5,A线程在临时变量中分配值4进行计数.

6)B线程以6为时间单位在临时变量中分配值4进行计数.

7)最终结果是A线程和B线程获得了相同的计算结果4,并且出现了非线程安全问题.

实际上,此示例是典型的销售场景. 五个销售人员,每个销售人员在售出产品后不能获得相同的剩余数量,必须在每个销售人员售出产品后才能获得,其余销售人员只有这样,您才能继续对新剩余项目减去1. 这时,您需要同步多个线程多线程技术问题解决,即使用顺序队列减去1并按如下所示更改代码:

公共类MyThread扩展了线程{

private int count = 5;

@Override

同步的public void run(){

super.run();

count-;

System.out.println(“由“ + this.currentThread(). getName()+”计算,count =” + count);

}

}

重新运行程序后,将不会显示相同的值,如图1-23所示.

通过在run()方法之前添加synced关键字,可以在执行run()方法时在队列中处理多个线程. 程调用run()方法之前,首先确定run()方法是否已锁定. 如果run()方法被锁定,则意味着其他线程正在调用run()方法,并且必须等待其他线程运行(). 调用完成后,线程可以执行run()方法,这也达到了将run()方法排队的目的,从而按顺序将count变量减少1. 同步可以锁定任何对象和方法,被锁定的代码称为“互斥区域”或“关键区域”.

当线程想要以同步方法执行代码时,该线程将首先尝试申请锁定. 如果可以应用锁定,则线程将同步执行代码. 如果无法应用该锁,则该线程将继续尝试申请该锁多线程技术问题解决,直到被应用为止,并且多个线程将同时争用该锁.


本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/jisuanjixue/article-266386-1.html

    相关阅读
      发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

      热点图片
      拼命载入中...