从网易的一道多线程笔试题学习wait与notify来控制线程同步

题目 : 有三个线程分别打印A、B、C,请用多线程编程实现,在屏幕上循环打印10次ABCABC…

package my.thread.test;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class PrintThreadExample {
    public static void main(String[] args) {
    PrintThreadExample example = new PrintThreadExample();

    LetterPrinter letterPrinter = example.new LetterPrinter();

    ExecutorService service = Executors.newFixedThreadPool(3);

    service.execute(example.new PrintRunnable(letterPrinter, ‘A‘));
    service.execute(example.new PrintRunnable(letterPrinter, ‘B‘));
    service.execute(example.new PrintRunnable(letterPrinter, ‘C‘));

    service.shutdown();
  }

  private class LetterPrinter {
      private char letter = ‘A‘;

    public void print() {
      System.out.println(letter);
      if (‘C‘ == letter) {
        System.out.println();
      }
    }

    public void nextLetter() {
      switch (letter) {
      case‘A‘:
        letter = ‘B‘;
        break;
      case‘B‘:
        letter = ‘C‘;
        break;
      case‘C‘:
        letter = ‘A‘;
        break;
      }
    }

    /**
     * @return the letter
     */public char getLetter() {
      return letter;
    }

  }

  private class PrintRunnable implements Runnable {
    private LetterPrinter letterPrinter = null;

    private char letter = ‘ ‘;

    /**
     * @param letterPrinter
     * @param letter
     */public PrintRunnable(LetterPrinter letterPrinter, char letter) {
      super();
      this.letterPrinter = letterPrinter;
      this.letter = letter;
    }

    public void run() {
      for (int i = 0; i < 10; i++) {
        //synchronized (letterPrinter) {
          while (letter != letterPrinter.getLetter()) {
            try {
              letterPrinter.wait();
            } catch (InterruptedException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
            }
         // }

          letterPrinter.print();
          letterPrinter.nextLetter();
          letterPrinter.notifyAll();

        }
      }

    }

  }

}
Exception in thread "pool-1-thread-2" Exception in thread "pool-1-thread-3" java.lang.IllegalMonitorStateException
    at java.lang.Object.wait(Native Method)
    at java.lang.Object.wait(Unknown Source)
    at my.thread.test.PrintThreadExample$PrintRunnable.run(PrintThreadExample.java:72)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
java.lang.IllegalMonitorStateException
    at java.lang.Object.wait(Native Method)
    at java.lang.Object.wait(Unknown Source)
    at my.thread.test.PrintThreadExample$PrintRunnable.run(PrintThreadExample.java:72)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)

如果注释掉synchronized (letterPrinter) 则会抛出IllegalMonitorStateException异常,查了一下文档,如下:

如果当前线程不是对象监视器的拥有者的话则会抛出IllegalMonitorStateException异常。也就是当需要调用一个对象的wait方法的时候,首先需要获取这个对象,否则会出现问题。Statck上一个回答解释了原因,如下:

这个例子说明了加锁的原因之一是为了操作原子性,以免引起死锁的问题

时间: 2024-07-28 12:57:42

从网易的一道多线程笔试题学习wait与notify来控制线程同步的相关文章

多线程面试题系列(5):经典线程同步 关键段CS

上一篇提出了一个经典的多线程同步互斥问题,本篇将用关键段CRITICAL_SECTION来尝试解决这个问题.本文首先介绍下如何使用关键段,然后再深层次的分析下关键段的实现机制与原理.关键段CRITICAL_SECTION一共就四个函数,使用很是方便.下面是这四个函数的原型和使用说明. 函数功能:初始化 函数原型: void InitializeCriticalSection(LPCRITICAL_SECTIONlpCriticalSection); 函数说明:定义关键段变量后必须先初始化. 函数

&lt;转&gt;网易2016实习生前端笔试题部分总结

网易2016实习生前端笔试题部分总结 原文地址:http://www.cnblogs.com/venoral/p/5325202.html 这只是部分题,答案为个人观点如有错误欢迎指出,感觉考点都挺基础,但是很注重考细节方面,通过整理也知道自己在CSS3和HTML5,网络知识等方面的不足还是得多学多练多思考.攒rp,希望自己在明天360笔试中能轻松答过~ css 1.多选 //HTML <p>很长的一段文字,很长的一段文字,很长的一段文字,特别长的文字</p> //CSS p{ w

网易2017秋招笔试题3:最长公共子括号序列长度

[问题来源]网传的2017网易秋招笔试题 [问题描述] [算法思路] 下面的解题思路摘自  http://www.cnblogs.com/Atanisi/p/7500186.html 刚看到题我就想到暴力解,深搜出所有合法的括号序列,再依次比较公共子序列的长度,返回最长的.但是深搜一般和路径有关,这道题仅仅需要最大公共子序列的长度.而我们发现最大公共子序列的长度就是 s.size() - 1(当且仅当修改距离为 1 时 LCS 最大), 那么我们就想到,可以变换 s 中一个括号的位置,枚举所有的

多线程笔试题(linux)

子线程循环 10 次,接着主线程循环 100 次,接着又回到子线程循环 10 次,接着再回到主线程又循环 100 次,如此循环50次,试写出代码. #include <stdio.h> #include <stdlib.h> #include <string.h> #include <pthread.h> pthread_attr_t attr; pthread_mutex_t mutex; pthread_cond_t cond; pthread_t pi

笔试题学习(dp,重叠子问题,卡特兰数,手电过桥,最长公共子序列)

卡特兰数:https://blog.csdn.net/doc_sgl/article/details/8880468 dp,重叠子问题:https://www.cnblogs.com/hapjin/p/5572483.html 美团2016校招笔试题:https://zhuanlan.zhihu.com/p/29308843 大厂面试经验:https://mp.weixin.qq.com/s?__biz=MzI2OTQxMTM4OQ==&mid=2247484859&idx=1&s

VB.net学习笔记(二十七)线程同步上

X夫妇二人试图同时从同一账户(总额1000)中支取1000.由于余额有1000,夫妇各自都满足条件,于是银行共支付2000.结果是银行亏了1000元.这种两个或更多线程试图在同一时刻访问同一资源来修改其状态,并产生不良后果的情况被称做竞争条件. 为避免竞争条件,需要使Withdraw()方法具有线程安全性,即在任一时刻只有一个线程可以访问到该方法. 一.线程同步 多个线程读或写同一资源,就会造成错漏状况,这时就需要线程同步.同步就是协同步调,按预定的先后次序进行运行.如:你说完,我再说.线程A与

出场率比较高的一道多线程安全面试题

这个问题是 Java 程序员面试经常会遇到的吧. 工作一两年的应该都知道 ArrayList 是线程不安全的,要使用线程安全的就使用 Vector,这也是各种 Java 面试宝典里面所提及的,可能很多工作好几年的程序员都停留在这个知识面上. 先说说为什么 ArrayList 是线程不安全的吧,来看以下的代码. /** * 微信公众号:Java技术栈 */ public class TestArrayList { private static List<Integer> list = new A

一道搜狗笔试题引发的思考

一: 给定一个数组a[N],我们希望构造数组b[N],其中b[i]=a[0]*a[1]*...*a[N-1]/a[i]. 在构造过程: 1.不允许使用除法: 2.要求O(1)空间复杂度和O(n)时间复杂度: 3.除遍历计数器与a[N] b[N]外,不可使用新的变量(包括栈临时变量.对空间和全局静态变量等): void makeArray(int a[],int b[],int len) { int i,j; b[0] = 1; for(i=1;i<len;i++) { b[i] = b[i-1]

详解一道C++笔试题,考察重载、覆盖、多态

C++版看到的,说是面试宝典里的题目,考察重载.覆盖.多态等概念,比较有代表性.今天早上远程辅导 Yan Wang 同学学习 Qt 时还想到了这个题目,如果你能够正确理解这个题目,说明对于 C++ 中的函数重载.覆盖.虚函数.多态等有了正确的认识.然后呢,再来学习 Qt 就顺风顺水了. 博文决赛,请给我投票:Qt Quick 图像处理实例之美图秀秀(附源码下载),谢谢. 原文地址: Qt Quick 图像处理实例之美图秀秀(附源码下载) 题目是酱紫的: #include <iostream>