多线程

时间:2016-03-05 03:00:20

标签: java multithreading synchronized

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

示例:

public class Test {

    private static int count = 0;

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

如果测试类是由对象使用的话,那么将synchronized添加到incrementcount()是有意义的。但是,如果您不延长ThreadRunnable那么使用synchronized编写的内容。

3 个答案:

答案 0 :(得分:2)

同步不适用于线程或Runnables,它用于多个线程访问的数据结构,以确保每个线程以不会破坏其数据的方式访问它们。你自己的例子是一个基本的例子,其中count以一种不是线程安全的方式递增(using ++, see this question),所以它需要锁定以确保一次只有一个线程可以递增它。 / p>

如果有其他访问计数的代码,则还需要进行同步,以便可以看到对计数的更新。如果你所做的只是增加一个计数器,那么使用像java.util.concurrent.atomic.AtomicInteger这样的类更有意义,你可以完全没有synchronized关键字。

对于使用synchronized来理解它确实假设有多个线程。即使您自己的代码没有创建新线程,也可能存在多个线程正在调用您的代码的情况(例如在servlet容器中,容器管理线程池并为每个传入请求分配线程)。

答案 1 :(得分:1)

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

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

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

我正在展示" synchronized"在对象级别而不是类级别(static synchronized

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关键字,则输出无法预测,如下所示。

java SynchronizedDemo
Count:2
Count:3
Count:2
Count:7
Count:6
Count:5
Count:4
Count:10
Count:9
Count:8

如果我改变

public void incrementCount() {

public synchronized void incrementCount() {

输出是:

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.

查看oracle文档page以便更好地理解。

缺少&#34; static synchronized&#34;

的代码演示
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();  
        }
    }
}

输出:

Count:5
Count:4
Count:3
Count:2
Count:10
Count:9
Count:8
Count:7
Count:6

制作后

public static void incrementCount() {

ppublic static synchronized void incrementCount() {

输出:

Count:1
Count:2
Count:3
Count:4
Count:5
Count:6
Count:7
Count:8
Count:9
Count:10

在此示例中,与之前不同,我们创建了10个不同的Test个实例。

答案 2 :(得分:0)

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

  1. 将临时变量设置为1+i
  2. 将变量i设置为临时变量。
  3. 但是,假设执行i++的线程在步骤1之后被中断,并且中断线程也调用i++。然后,这会发生:

    (假设i=1

    1. 原始主题:将临时变量1设置为1+i2
    2. 中断线程:将临时变量2设置为i+1,同时2
    3. 中断线程:将i设置为临时变量2。现在i=2
    4. 原始主题:将i设置为临时变量1。现在i=2
    5. 问题是,如果i++被调用两次,则应为3,而不是2

      synchronized void会锁定变量i,直到整个void完成执行。例如:

      1. 原始主题:将临时变量1设置为1+i2。锁定变量i
      2. 中断线程:TRIES将临时变量2设置为i+1,但由于锁定变量i
      3. 而等待
      4. 原始主题:将i设置为临时变量1。现在i=2。变量i现已解锁。
      5. 中断线程&#34;通知&#34; i已解锁,因此它将临时变量2设置为i+1 3
      6. 中断线程i设置为3,这是预期的行为。
      7. synchronized void本质上是暂时锁定变量,以避免混淆程序的执行。