首页 > 技术文章 > 网易多线程笔试题目学习

Guoyutian 2016-07-17 22:43 原文

题目:一个线程打印 1~52,另一个线程打印字母A-Z。打印顺序为12A34B56C……5152Z。 

 

package my.thread.test;  
  
import java.util.concurrent.ExecutorService;  
import java.util.concurrent.Executors;  
import java.util.concurrent.locks.Condition;  
import java.util.concurrent.locks.Lock;  
import java.util.concurrent.locks.ReentrantLock;  
  
/** 
 * 一个线程打印 1~52,另一个线程打印字母A-Z。打印顺序为12A34B56C……5152Z。 
 *  
 * @author Eric 
 *  
 */  
public class ThreadCommunicationTest {  
  
    private final Lock lock = new ReentrantLock();  
  
    private final Condition conditionA = lock.newCondition();  
    private final Condition conditionB = lock.newCondition();  
  
    private static char currentThread = 'A';  
  
    public static void main(String[] args) {  
  
        ThreadCommunicationTest test = new ThreadCommunicationTest();  
  
        ExecutorService service = Executors.newCachedThreadPool();  
  
        service.execute(test.new RunnableA());  
        service.execute(test.new RunnableB());  
  
        service.shutdown();  
  
    }  
  
    private class RunnableA implements Runnable {                 
  
        public void run() {  
            for (int i = 1; i <= 52; i++) {  
                lock.lock();  
  
                try {  
                    while (currentThread != 'A') {  
                        try {  
                            conditionA.await();  
                        } catch (InterruptedException e) {  
                            // TODO Auto-generated catch block  
                            e.printStackTrace();  
                        }  
                    }  
  
                    System.out.println(i);  
                    if (i % 2 == 0) {  
                        currentThread = 'B';  
                        conditionB.signal();  
                    }  
                } finally {  
                    lock.unlock();  
                }  
            }  
  
        }  
  
    }  
  
    private class RunnableB implements Runnable {  
  
        @Override  
        public void run() {  
            for (char c = 'A'; c <= 'Z'; c++) {  
                lock.lock();  
                try {  
                    while (currentThread != 'B') {  
                        try {  
                            conditionB.await();  
                        } catch (InterruptedException e) {  
                            // TODO Auto-generated catch block  
                            e.printStackTrace();  
                        }  
                    }  
  
                    System.out.println(c);  
                    currentThread = 'A';  
                    conditionA.signal();  
                } finally {  
                    lock.unlock();  
                }  
            }  
  
        }  
  
    }  
}  

上面的代码是网上找的,通过研究,学习了很多:

1.为什么是while而不是用if来判断条件,做了如下的实验

package test;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 一个线程打印 1~52,另一个线程打印字母A-Z。打印顺序为12A34B56C……5152Z。
 *
 * @author Eric
 *
 */
public class ThreadCommunicationTest {

    private final Lock lock = new ReentrantLock();

    private final Condition conditionA = lock.newCondition();
    private final Condition conditionB = lock.newCondition();

    private static char currentThread = 'A';

    public static void main(String[] args) {

        ThreadCommunicationTest test = new ThreadCommunicationTest();

        ExecutorService service = Executors.newCachedThreadPool();

        RunnableA a = test.new RunnableA();
        service.execute(a);

        service.execute(a);



        RunnableB b = test.new RunnableB();
        service.execute(b);

        service.shutdown();


    }

    private class RunnableA implements Runnable {

        public void run() {
            for (int i = 1; i <= 100; i++) {
                lock.lock();

                try {
                    if (currentThread != 'A') {
                        try {
                            conditionA.await();
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }

                    System.out.println(i + "线程名称" + Thread.currentThread().getName());
                    if (i % 2 == 0) {
                        currentThread = 'B';
                        conditionB.signal();
                    }
                } finally {
                    lock.unlock();
                }
            }

        }

    }

    private class RunnableB implements Runnable {

        @Override
        public void run() {
            for (char c = 'A'; c <= 'Z'; c++) {
                lock.lock();
                try {
                    while (currentThread != 'B') {
                        try {
                            conditionB.await();
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }

                    System.out.println(c + "线程名称" + Thread.currentThread().getName());
                    currentThread = 'A';
                    conditionA.signalAll();
                } finally {
                    lock.unlock();
                }
            }
        }

    }
}

 开了两个线程用于执行任务A,并把判断条件改为if,则会出现如下的结果:

说明在currentThread = B的时候执行了任务A,因为当任务B调用signalAll的时候,将两个任务A线程都唤醒,假设此时任务A的一个线程输出了两个数并把currentThread条件设为了B,此时另一个任务A线程和任务B线程会同时竞争锁,如果任务A线程竞争锁成功,则会出现混乱的情况,所以要用while来进行判断

推荐阅读