为什么主要顺序中没有呼叫? [英] Why aren't the calls in main sequential?

查看:114
本文介绍了为什么主要顺序中没有呼叫?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在阅读一些关于线程/同步的简单示例,该书声称使用 synchronized 将允许在同一个线程上调用一个线程来访问该方法实例。它确实按照承诺进行了序列化,但它似乎是在同步 <$ c中创建的第三个来电者的约9/10倍下面是$ c> main 方法。此代码是示例代码,显示没有同步方法的问题。

I was going through some simple examples on threading/synchronizing from a book that claims the use of synchronized will allow access to the method by one thread being called on the same instance. It does serialize as promised but it seems that about 9/10 times the third Caller created in the Synch main method below comes before the second. This code is the example code showing the issues without a synchronized method.

class CallMe {
    void call(String msg) {
        System.out.print("[" + msg);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            System.out.println("CallMe Interrupted");
        }
        System.out.println("]");
    }
}

class Caller implements Runnable {
    String msg;
    CallMe target;
    Thread t;

    public Caller (CallMe target, String msg) {
        this.target = target;
        this.msg = msg;
        t = new Thread(this);
        t.start();
    }

    @Override
    public void run() {
        target.call(msg);
    }
}

class Synch {
    public static void main(String args[]) {
        CallMe target = new CallMe();
        Caller c1 = new Caller(target, "Hello");
        Caller c2 = new Caller(target, "Synchronized");
        Caller c3 = new Caller(target, "World");

        try {       
            c1.t.join();
            c2.t.join();
            c3.t.join();        
        } catch (InterruptedException e) {
            System.out.println("Synch Interrupted");
        }
    }
}

这本书展示了两种方法处理这个问题,它们是 -

synchronized void call(String msg){...}

public void run(){synchronized(target){...}}


很明显,两个选项都有效,因为它与原始版本相反代码,括号内的单词是一致的...

The book shows two ways to deal with the issue, they are -
synchronized void call(String msg) {...} and
public void run() { synchronized (target) {...} }

It's clear that both options work because, as opposed to the original code, the bracketed words are consistent like...


[Hello]

[World](约90%)呼叫倒退的时间)

[已同步](1 /很多已同步为第一个消息)

[Hello]
[World] (about 90% of the time the calls are backwards)
[Synchronized](1/many have Synchronized as the first msg)

......原始代码没有押韵或理由。所以我知道它正常工作,可以通过在每个 Caller 实例化上放置断点来直接看到。当我这样做时,它显然对我来说很有效。

...there's no rhyme or reason to the original code. So I know it's "working" and can be seen directly by placing breakpoints on each of the Caller instantiations. It works every time, obviously to me, when I do.

为什么第三个来电者一直致电来电之前第二个?

Why is the third Caller consistently calling call before the second?

推荐答案

根据定义,线程并行运行,并且没有优先于任何其他线程。

Threads by definition run in parallel, and none is given precedence over any other.

一旦线程全部启动,它基本上是随机的,将首先运行,一般来说,第一个启动将有一个轻微的先发制人,但与启动的开销相比,先发制人是微不足道的线程等。

Once the threads are all launched it is essentially random which will run first, in general the first one launched will have a slight "head start" but that head start is tiny compared to the overhead of launching threads etc.

你的特定环境的怪癖恰好偏向于一个线程,结果可能在不同的系统上有所不同,当然不应该依赖。

A quirk of your particular environment just happens to be favoring one thread, the results may well vary on different systems and certainly shouldn't be relied on.

顺便提一下,这是一种不好的做法,原因如下:

Incidentally this is bad practice for a number of reasons:

public Caller (CallMe target, String msg) {
    this.target = target;
    this.msg = msg;
    t = new Thread(this);
    t.start();
}

(实际上你可能收到编译器警告)。

(You probably got a compiler warning in fact).

更好的是提供一个开始方法

Much better is to provide a start method

public Caller start() {
    t.start();
    return this;
}

然后再做

new Caller(target, msg).start();

这绝对可以确保Caller对象在Thread开始处理之前已完全初始化并准备就绪。

This absolutely ensures that the Caller object is fully initialized and ready to go before the Thread starts processing it.

这篇关于为什么主要顺序中没有呼叫?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆