zoukankan      html  css  js  c++  java
  • System.out.println 的多线程并发问题

    假设println函数的參数为常量则不会出现线程并发问题,可是假设參数为表达式形式。则JVM在运行println函数的时候会分为几步来运行,从而造成并发问题。

    例如以下样例所看到的:

    package xiaoye.java;
    
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.atomic.AtomicLong;
    
    public class Test
    {
    	public static void main(String[] args)
    	{
    		ExecutorService pool = Executors.newFixedThreadPool(2);
    		Runnable t1 = new MyRunnable("张三", 2000);
    		Runnable t2 = new MyRunnable("李四", 3600);
    		Runnable t3 = new MyRunnable("王五", 2700);
    		Runnable t4 = new MyRunnable("老张", 600);
    		Runnable t5 = new MyRunnable("老牛", 1300);
    		Runnable t6 = new MyRunnable("老朱", 800);
    		//运行各个线程
    		pool.execute(t1);
    		pool.execute(t2);
    		pool.execute(t3);
    		pool.execute(t4);
    		pool.execute(t5);
    		pool.execute(t6);
    		//关闭线程池
    		pool.shutdown();
    	}
    }
    
    class MyRunnable implements Runnable
    {
    	private static AtomicLong aLong = new AtomicLong(10000); //原子量。每一个线程都能够自由操作
    	private String name; //操作人
    	private int data; //操作数
    
    	MyRunnable(String name, int data)
    	{
    		this.name = name;
    		this.data = data;
    	}
    	public void run()
    	{
    		Thread.yield();
    		System.out.println(name + "运行了" + data + "。当前剩余金额:" + aLong.addAndGet(data));
    	}
    }

    经过多次运行,当中一次结果例如以下:
            李四运行了3600,当前剩余金额:15600
            王五运行了2700,当前剩余金额:18300
            老张运行了600。当前剩余金额:18900
            老牛运行了1300,当前剩余金额:20200
            老朱运行了800。当前剩余金额:21000
            张三运行了2000。当前剩余金额:12000

    对于 

    System.out.println(name + "运行了" + data + ",当前剩余金额:" + aLong.addAndGet(data));


    经过反编译后得到例如以下实际代码:

    System.out.println((new StringBuilder(String.valueOf(name))).append("运行了").append(data).append(",当前剩余金额:").append(aLong.addAndGet(data)).toString());

    而对于System.out.println() 方法,它的运行代码例如以下:

        public void println(String x) {
            synchronized (this) {
                print(x);
                newLine();
            }
        }

    所以。输出过程须要经过两个步骤,转化字符串和同步输出。

    实际上的运行过程是: 张三——李四——王五——老张——老牛——老朱,而实际上输出 张三 却是称为最后一个输出的。这是由于 张三 在或的锁之前被打断了。

    假设我们想要输出正确的运行顺序,能够加一个显示锁:

    package xiaoye.java;
    
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.atomic.AtomicLong;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class Test {
    	public static void main(String[] args) {
    		ExecutorService pool = Executors.newFixedThreadPool(2);
    		Lock lock = new ReentrantLock(false);
    		Runnable t1 = new MyRunnable("张三", 2000, lock);
    		Runnable t2 = new MyRunnable("李四", 3600, lock);
    		Runnable t3 = new MyRunnable("王五", 2700, lock);
    		Runnable t4 = new MyRunnable("老张", 600, lock);
    		Runnable t5 = new MyRunnable("老牛", 1300, lock);
    		Runnable t6 = new MyRunnable("老朱", 800, lock);
    		// 运行各个线程
    		pool.execute(t1);
    		pool.execute(t2);
    		pool.execute(t3);
    		pool.execute(t4);
    		pool.execute(t5);
    		pool.execute(t6);
    		// 关闭线程池
    		pool.shutdown();
    	}
    }
    
    class MyRunnable implements Runnable {
    	private static AtomicLong aLong = new AtomicLong(10000); // 原子量,每一个线程都能够自由操作
    	private Lock lock;
    	private String name; // 操作人
    	private int data; // 操作数
    
    	MyRunnable(String name, int data, Lock lock) {
    		this.name = name;
    		this.data = data;
    		this.lock = lock;
    	}
    
    	public void run() {
    		lock.lock();
    		System.out.println(name + "运行了" + data + ",当前剩余金额:"
    				+ aLong.addAndGet(data));
    		lock.unlock();
    	}
    }

    这样,不管怎样执行,程序的输出顺序和操作的执行顺序都保持一致。

  • 相关阅读:
    hlgoj 1766 Cubing
    Reverse Linked List
    String to Integer
    Bitwise AND of Numbers Range
    Best Time to Buy and Sell Stock III
    First Missing Positive
    Permutation Sequence
    Next Permutation
    Gray Code
    Number of Islands
  • 原文地址:https://www.cnblogs.com/zhchoutai/p/7088586.html
Copyright © 2011-2022 走看看