首页
学习
活动
专区
圈层
工具
发布

多线程
EN

Stack Overflow用户
提问于 2016-03-05 03:00:20
回答 3查看 155关注 0票数 2

我有一个多线程的想法,但我从来没有工作过。所以,当我在工作中看到我的申请时.我还没有看到任何类扩展线程创建Thread。因此,当两个对象试图同时访问一个变量时,使用synchronized关键字。我们使用同步来避免冲突。

示例:

代码语言:javascript
复制
public class Test {

    private static int count = 0;

    public static synchronized void incrementCount() {
        count++;
    }
} 

如果对象正在使用测试类,那么将synchronized添加到incrementcount()是有意义的。但是,当您不扩展ThreadRunnable时,编写synchronized的用途是什么。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-03-06 16:08:25

类不需要extend Threadimplements Runnable将其方法标记为同步以防止多线程访问

您的类可能是其他线程类的参数,而该线程类可能有多个实例。为了提供数据的强一致性,您必须保护代码和数据的关键部分。

只需更改代码示例,如下所示。

我演示的是"synchronized“,而不是类级别( static synchronized)。

代码语言:javascript
复制
class Test {
    private int count = 0;
    public void incrementCount() {
        count++;
        System.out.println("Count:"+count);
    }
} 
class MyRunnable implements Runnable{
    private Test test = null;
    public MyRunnable(Test t){
        this.test = t; 
    }
    public void run(){
        test.incrementCount();
    }
}
public class SynchronizedDemo{
    public static void main(String args[]){
        Test t = new Test();
        for ( int i=0; i<10; i++){
            new Thread(new MyRunnable(t)).start();  
        }
    }
}

您的类Test已作为参数传递给线程MyRunnable。现在,您已经创建了多个线程实例。在没有synchronized关键字的情况下,输出是不可预测的,如下所示。

代码语言:javascript
复制
java SynchronizedDemo
Count:2
Count:3
Count:2
Count:7
Count:6
Count:5
Count:4
Count:10
Count:9
Count:8

如果我改变了

代码语言:javascript
复制
public void incrementCount() {

代码语言:javascript
复制
public synchronized void incrementCount() {

产出如下:

代码语言:javascript
复制
Count:1
Count:2
Count:3
Count:4
Count:5
Count:6
Count:7
Count:8
Count:9
Count:10

另外,您已经将您的方法设置为static synchronizedThat means lock is maintained at class level instead of object level.

查看甲骨文文档页面,以更好地理解。

没有"static synchronized“的代码演示

代码语言:javascript
复制
class Test {
    private static int count = 0;
    public static void incrementCount() {
        count++;
        System.out.println("Count:"+count);
    }
} 
class MyRunnable implements Runnable{
    private Test test = null;
    public MyRunnable(Test t){
        this.test = t; 
    }
    public void run(){
        test.incrementCount();
    }
}
public class SynchronizedDemo{
    public static void main(String args[]){
        for ( int i=0; i<10; i++){
            Test t = new Test();
            new Thread(new MyRunnable(t)).start();  
        }
    }
}

产出:

代码语言:javascript
复制
Count:5
Count:4
Count:3
Count:2
Count:10
Count:9
Count:8
Count:7
Count:6

制作后

代码语言:javascript
复制
public static void incrementCount() {

代码语言:javascript
复制
ppublic static synchronized void incrementCount() {

产出:

代码语言:javascript
复制
Count:1
Count:2
Count:3
Count:4
Count:5
Count:6
Count:7
Count:8
Count:9
Count:10

在这个例子中,与前面的不同,我们创建了10个不同的Test实例。

票数 1
EN

Stack Overflow用户

发布于 2016-03-05 03:10:47

同步不是用于线程或Runnable,而是用于由多个线程访问的数据结构,以确保每个线程以不破坏其数据的方式访问它们。您自己的示例是这种情况的基本情况,计数以非threadsafe (使用++,请参阅此问题)的方式递增,因此需要锁定以确保一次只能增加一个线程。

如果有其他访问计数的代码,那么它也需要同步,这样它就可以看到对count的更新。如果您所做的只是递增一个计数器,那么使用像java.util.concurrent.atomic.AtomicInteger这样的类就更有意义了,而且您可以完全不使用同步关键字。

为了使同步化有意义,它确实假定存在多个线程。即使您自己的代码没有创建新线程,也可能存在多个线程正在调用您的代码的情况(例如在servlet容器中,容器管理线程池并为每个传入请求分配一个线程)。

票数 2
EN

Stack Overflow用户

发布于 2016-03-05 03:14:07

i++,即使它看起来像一个指令,实际上是多个指令:

  1. 将临时变量设置为1+i
  2. 将变量i设置为临时变量。

但是,假设执行i++的线程在步骤1之后被中断,而中断线程也调用i++。然后,这种情况就会发生:

(假设i=1)

  1. 原始线程:将临时variable1设置为1+i2
  2. 中断线程:将临时variable2设置为i+1,也将2设置为
  3. 中断线程:i设置为临时variable2。现在i=2
  4. 原始线程:i设置为临时variable1。现在i=2

问题是,如果i++被两次调用,那么它应该是3,而不是2

synchronized void将对变量i设置一个锁,直到整个void完成执行。例如:

  1. 原始线程:将临时variable1设置为1+i2。对变量i设置一个锁。
  2. 中断线程:尝试将临时variable2设置为i+1,但由于变量i上的锁而等待
  3. 原始线程:i设置为临时variable1。现在是i=2。变量i现在已解锁。
  4. 中断线程:“注意到”i已被解锁,因此它将临时variable2设置为i+1,即3
  5. 中断线程:i设置为3,这是预期的行为。

synchronized void本质上是暂时锁定变量,以避免混淆程序的执行。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35809464

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档