为什么我们不应该使用与run方法同步?

时间:2017-01-25 04:38:17

标签: java multithreading

每次运行此程序时,我都会得到不同的输出。 有没有办法只在run方法中获得一致的输出?

public class MultiBasic1 {

    public static void main(String[] args) {
        ChildThread th1=new ChildThread();
        ChildThread th2= new ChildThread();
        ChildThread th3= new ChildThread();
        ChildThread th4= new ChildThread();
        th1.start();
        th2.start();
        th3.start();
        th4.start();
    }
}

class ChildThread extends Thread{

    synchronized public void run(){
        for(int i=1; i<=5; i++)
            System.out.println(i);
    }
}

3 个答案:

答案 0 :(得分:2)

因为您正在创建ChildThread的新实例,所以允许每个线程无限制地访问run方法,因为实际只有一个线程正在访问该方法。

要演示synchronized如何工作,您需要拥有某种共享资源,例如每个线程可以与之交互的Object

public class Test {

    public static void main(String[] args) {
        Action action = new Action();
        Thread t1 = new Thread(new Runner(action), "1");
        Thread t2 = new Thread(new Runner(action), "2");
        Thread t3 = new Thread(new Runner(action), "3");
        Thread t4 = new Thread(new Runner(action), "4");
        Thread t5 = new Thread(new Runner(action), "5");


        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
    }

    public static class Runner implements Runnable {
        private Action action;

        public Runner(Action action) {
            this.action = action;
        }

        @Override
        public void run() {
            action.makeItSo();
        }

    }

    public static class Action {
        public synchronized void makeItSo() {
            for (int index = 0; index < 10; index++) {
                System.out.println(Thread.currentThread().getName() + " - " + index);
            }
        }
    }

}

上面的示例演示了只有一个线程可以在makeItSo方法中运行,但是,也不能保证允许哪个线程运行(即顺序)

答案 1 :(得分:1)

为什么你得到不同的输出?

答案: synchronized在进入同步块或方法之前需要一个锁定对象。

在这种情况下,对执行该方法的对象进行锁定,因此线程1锁定在对象th1上,线程2锁定在th2上,依此类推。

因此,所有线程都锁定到不同的对象上,并允许它们同时运行。

如何获得一致的输出?

答案

选项1:您可以使用join将线程连接到主线程 公共类MultiBasic1 {

public static void main(String[] args) throws InterruptedException {
    ChildThread th1=new ChildThread();
    ChildThread th2= new ChildThread();
    ChildThread th3= new ChildThread();
    ChildThread th4= new ChildThread();

    th1.setName("A");
    th2.setName("B");
    th3.setName("C");
    th4.setName("D");

    th1.start();
    th1.join();
    th2.start();
    th2.join();
    th3.start();
    th3.join();
    th4.start();
    th4.join();
}

}

class ChildThread扩展了Thread {

public void run(){
    for(int i=1; i<=5; i++)
        System.out.println(i + " " + getName());
}

}

选项2:为synchronized块提供共享对象以同步线程

公共类MultiBasic1 {

public static void main(String[] args) throws InterruptedException {
    ChildThread th1=new ChildThread();
    ChildThread th2= new ChildThread();
    ChildThread th3= new ChildThread();
    ChildThread th4= new ChildThread();

    th1.setName("A");
    th2.setName("B");
    th3.setName("C");
    th4.setName("D");

    th1.start();
    th2.start();
    th3.start();
    th4.start();
}

}

class ChildThread扩展了Thread {

private static final Object lock = new Object();
public void run(){

    synchronized (lock) {
        for(int i=1; i<=5; i++)
            System.out.println(i + " " + getName());
    }

}

}

答案 2 :(得分:0)

这里甚至不需要同步,因为您使用不同的对象来调用run方法。

当一个对象的多个线程在图片中时,同步有效。

如果您执行以下操作,上面的示例会更有意义。

public class MultiBasic1 {

    public static void main(String[] args) {
        ChildThread th1=new ChildThread();
        Thread t1 = new Thread(th1);
        Thread t2 = new Thread(th1);
        Thread t3 = new Thread(th1);
        Thread t4 = new Thread(th1);
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}

class ChildThread extends Thread{

    synchronized public void run(){
        for(int i=1; i<=5; i++)
            System.out.println(i);
    }
}