简单的单线程队列 -- 工作的时候遇到劣质打印机。给打印机发消息,打印机就会打印,如果在打印机还在打印的时候,就

再发消息打印,就会出现消息丢失。所以需要给上一个任务一些处理的间隔时间.

单线程的消息队列示例

  1. package demo1;
  2. import java.util.LinkedList;
  3. public class Main {
  4. /**
  5. * @param args
  6. */
  7. private static Thread thread;
  8. private static LinkedList<Runnable> list = new LinkedList<Runnable>();
  9. static int test = 0;
  10. public static void main(String[] args) {
  11. // TODO Auto-generated method stub
  12. final long time = System.currentTimeMillis();
  13. for (int i = 0; i < 20; i++) {
  14. tastEvent(new Runnable() {
  15. public void run() {
  16. try {
  17. Thread.sleep(500);
  18. } catch (InterruptedException e) {
  19. // TODO Auto-generated catch block
  20. e.printStackTrace();
  21. }
  22. System.out
  23. .println("第"
  24. + (++test)
  25. + ("个任务  耗时:" + (System
  26. .currentTimeMillis() - time)));
  27. }
  28. });
  29. }
  30. }
  31. public static void tastEvent(Runnable r) {
  32. synchronized (list) {
  33. list.add(r);
  34. }
  35. if (thread == null) {
  36. thread = new Thread(run);
  37. thread.start();
  38. }
  39. }
  40. static Runnable run = new Runnable() {
  41. @Override
  42. public void run() {
  43. // TODO Auto-generated method stub
  44. synchronized (list) {
  45. while (!list.isEmpty()) {
  46. // new Thread(list.poll()).start();
  47. list.poll().run();
  48. }
  49. thread = null;
  50. }
  51. }
  52. };
  53. }

工作的时候遇到非常大的并发的情况,比如机器1秒只支持1000的并发,但是1秒接收了4000的并发。服务器就会崩掉。

最好将并发放到队列中,按1000的并发吞吐量来处理,这就是异步队列应用。

一个工程交给一个人做,需要花费3个月,交给2个人做,需要2个人做需要2个月,需要3个人做需要1个月半.....100.人.....1000人,几年也完不成。

带上以上道理看待以下的代码

观察以下代码(复制到android工程下运行):最后耗时约1600毫秒 而使用android的AsyncTask类来改写这段代码只需要耗时约200

  1. final long  timer=System.currentTimeMillis();
  2. count=0;
  3. final Handler h=new Handler();
  4. for(int k=0;k<100;k++){
  5. new Thread(){
  6. @Override
  7. public void run() {
  8. // TODO Auto-generated method stub
  9. try {
  10. Thread.sleep(10);
  11. } catch (InterruptedException e) {
  12. // TODO Auto-generated catch block
  13. e.printStackTrace();
  14. }
  15. h.post(new Runnable() {
  16. @Override
  17. public void run() {
  18. Toast.makeText(getApplicationContext()," 耗时"+ (System.currentTimeMillis() - timer), 1).show();
  19. System.err.println("编号"+(count++)+"线程消耗了"+(System.currentTimeMillis()-timer));
  20. }
  21. });
  22. }
  23. }.start();

可见增加多线程不提高性能,反而因为系统在不同的线程之间切换降低效率。因此我们需要让线程有序执行任务

以下是异步多线程处理队列的demo

  1. package demo2;
  2. import demo2.Task.OnFinishListen;
  3. public class Main {
  4. /**
  5. * @param args
  6. */
  7. public static void main(String[] args) {
  8. // TODO Auto-generated method stub
  9. Task.setThreadMaxNum(3);
  10. for (int i = 0; i < 15; i++) {
  11. new Task() {
  12. @Override
  13. public Object obtainData(Task task, Object parameter)
  14. throws Exception {
  15. // TODO Auto-generated method stub
  16. Thread.sleep(500);
  17. return task.taskID;
  18. }
  19. }
  20. .setOnFinishListen(new OnFinishListen() {
  21. @Override
  22. public void onFinish(Task task, Object data) {
  23. // TODO Auto-generated method stub
  24. System.err.println("任务编号"+task.taskID+"任务完成");
  25. }
  26. })
  27. .setTaskID(i)
  28. .start();
  29. }
  30. }
  31. }
  1. package demo2;
  2. import java.util.HashMap;
  3. import java.util.Map;
  4. import java.util.Observable;
  5. import java.util.Observer;
  6. public abstract class Task<P,R> implements Runnable, Observer,TaskAction<P,R>{
  7. //设置最大任务数
  8. public static void setThreadMaxNum(int num) {
  9. TaskQueue.ThreadMaxNum = num<1?1:num>100?100:num;
  10. }
  11. public static enum TaskPriority {
  12. max, min;
  13. }
  14. /** 单例 可以提高性能 */
  15. protected final static Exception withoutException = new Exception(
  16. "The state is without");
  17. // 名字映射
  18. private static HashMap<String, Task> nameTasks;
  19. public static HashMap<String, Task> getNameTask() {
  20. if (nameTasks == null) {
  21. nameTasks = new HashMap<String, Task>();
  22. }
  23. return nameTasks;
  24. }
  25. public Task<P,R> setSingletonName(String singletonName) {
  26. this.singletonName = singletonName;
  27. return this;
  28. }
  29. public String getSingletonName() {
  30. return singletonName;
  31. }
  32. public interface OnStartListen {
  33. void onStart(Task t);
  34. }
  35. public interface OnProgressListen {
  36. void onProgress(Task task, int progress, Object data);
  37. }
  38. public static interface OnFinishListen<P,R> {
  39. void onFinish(Task<P,R> task, R data);
  40. }
  41. public interface OnSystemStartListen {
  42. void onSystemStart(Task task);
  43. }
  44. public interface OnSystemFinishListen {
  45. void OnSystemFinish(Task t, Object data);
  46. }
  47. /** 请求参数 */
  48. protected P parameter;
  49. /** 任务开始监听 */
  50. protected OnStartListen onStartListen;
  51. /** 任务进度监听 */
  52. protected OnProgressListen onProgressListen;
  53. /** 任务完成监听 */
  54. protected OnFinishListen<P,R> onFinishListen;
  55. /** 任务在队列中完成 监听 */
  56. protected OnSystemStartListen onSystemStartListen;
  57. /** 任务在队列中开始 监听 */
  58. protected OnSystemFinishListen onSystemFinishListen;
  59. /** 用于任务完成后发送消息 */
  60. /** 结果 */
  61. protected R result;
  62. /** 任务编号标示 */
  63. protected int taskID = -1;
  64. /** 任务名字标示 */
  65. /** 设置此任务名是否为单例,单例模式下,如果相同名字的任务未执行完,则无法添加新任务 */
  66. protected String singletonName;
  67. /** 保存一个对象 */
  68. protected Object tag;
  69. /** 获得当前自身线程的引用 在threadRun方法 */
  70. protected Thread thread;
  71. /** 重连次数 */
  72. protected int tryAgainCount = 1;
  73. /** 重连间隔 */
  74. protected int tryAgainTime = 1000;
  75. /** 默认优先级低 */
  76. protected TaskPriority priority = TaskPriority.min;
  77. protected HashMap<String,Object> dataMap;
  78. protected Task() {
  79. }
  80. // 任务状态
  81. public static enum TaskStatus {
  82. // 未处理 出错 完成 执行中 排除
  83. untreated, wait,error, finsh, running, without;
  84. }
  85. /** 状态 */
  86. TaskStatus status = TaskStatus.untreated;
  87. public void setWithout() {
  88. this.status = TaskStatus.without;
  89. }
  90. public void remove() {
  91. this.status = TaskStatus.without;
  92. }
  93. public TaskPriority getPriority() {
  94. return priority;
  95. }
  96. public void setPriority(TaskPriority priority) {
  97. this.priority = priority;
  98. }
  99. /** 启动线程 */
  100. public void start() {
  101. if (this.priority == null)
  102. this.priority = TaskPriority.min;
  103. synchronized (TaskQueue.tasks_wait) {
  104. if (getSingletonName() != null
  105. && Task.getNameTask().get(this.getSingletonName()) != null) {
  106. this.setWithout();
  107. } else {
  108. Task.getNameTask().put(this.getSingletonName(), this);
  109. }
  110. switch (priority) {
  111. case min:
  112. TaskQueue.tasks_wait.remove(this);
  113. TaskQueue.tasks_wait.add(this);
  114. break;
  115. case max:
  116. TaskQueue.tasks_wait.remove(this);
  117. TaskQueue.tasks_wait.addFirst(this);
  118. break;
  119. default:
  120. break;
  121. }
  122. // 启动此服务
  123. TaskQueue.serivesRun();
  124. }
  125. }
  126. /** 启动线程 */
  127. public void start(TaskPriority priority) {
  128. this.priority = priority;
  129. status=TaskStatus.wait;
  130. start();
  131. }
  132. /** 启动线程 */
  133. final void threadRun() {
  134. thread = new Thread(this);
  135. thread.start();
  136. }
  137. // 中断Execute方法
  138. public  void shutDownExecute(){};
  139. public  R cacheData(P parameter){
  140. return result;};
  141. // 禁止被重写
  142. public final Object Execute() throws Exception {
  143. // TODO Auto-generated method stub
  144. if (onStartListen != null)
  145. onStartListen.onStart(this);
  146. // 队列中回调
  147. if (onSystemStartListen != null)
  148. onSystemStartListen.onSystemStart(this);
  149. // 状态从未处理改变为处理中
  150. status = TaskStatus.running;
  151. // 获取最后一次是否错误
  152. Exception exception = null;
  153. // 是否有缓存数据如果没有
  154. if ((result = cacheData(parameter)) == null) {
  155. // 失败重联次数
  156. for (int i = 0; i < tryAgainCount; i++) {
  157. try {
  158. // 如果状态改变为排除则跳出失败重联
  159. if (status == TaskStatus.without) {
  160. break;
  161. }
  162. exception = null;
  163. result = obtainData(this, parameter);
  164. System.out.println("result=" + result);
  165. break;
  166. } catch (Exception e) {
  167. // TODO Auto-generated catch block
  168. if ((exception = e) == withoutException) {
  169. break;
  170. }
  171. e.printStackTrace();
  172. try {
  173. Thread.sleep(tryAgainTime);
  174. } catch (Exception e1) {
  175. // TODO Auto-generated catch block
  176. e1.printStackTrace();
  177. }
  178. }
  179. }
  180. }
  181. // 如果最后一次仍然失败则抛出
  182. if (exception != null) {
  183. throw exception;
  184. }
  185. // 如果状态改变为处理完但不通知
  186. if (status != TaskStatus.without) {
  187. if (onFinishListen != null) {
  188. //完成监听并将结果加入到主线程
  189. onFinishListen.onFinish(this, result);
  190. }
  191. ;
  192. }
  193. if (onSystemFinishListen != null) {
  194. onSystemFinishListen.OnSystemFinish(this, result);
  195. }
  196. status = TaskStatus.finsh;
  197. return result;
  198. }
  199. public abstract  R obtainData(Task<P,R> task, P parameter)throws Exception;
  200. @Override
  201. public void update(Observable observable, Object data) {
  202. // 移除观察
  203. observable.deleteObserver(this);
  204. // 中断 停止关闭连接
  205. this.shutDownExecute();
  206. this.setWithout();
  207. if (this.thread != null) {
  208. this.thread.interrupt();
  209. }
  210. // 错误尝试次数为0
  211. this.tryAgainCount = 0;
  212. };
  213. @Override
  214. public void run() {
  215. try {
  216. Execute();
  217. } catch (Exception e) {
  218. e.printStackTrace();
  219. status = TaskStatus.error;
  220. // 如果状态改变为处理完但不通知
  221. if (status != TaskStatus.without) {
  222. if (onFinishListen != null) {
  223. //将结果加入到主线程
  224. onFinishListen.onFinish(this, result);
  225. }
  226. }
  227. if (onSystemFinishListen != null) {
  228. onSystemFinishListen.OnSystemFinish(this, e);
  229. }
  230. }
  231. //递归 避免新开线程   唤醒等待中的任务
  232. TaskQueue.getRunnable().notifyWaitingTask();
  233. }
  234. public Object getTag() {
  235. return tag;
  236. }
  237. public Task setTag(Object tag) {
  238. this.tag = tag;
  239. return this;
  240. }
  241. public Thread getThread() {
  242. return thread;
  243. }
  244. public TaskStatus getStatus() {
  245. return status;
  246. }
  247. public Object getParameter() {
  248. return parameter;
  249. }
  250. public Task setParameter(P parameter) {
  251. this.parameter = parameter;
  252. return this;
  253. }
  254. public OnStartListen getOnStartListen() {
  255. return onStartListen;
  256. }
  257. public Task setOnStartListen(OnStartListen onStartListen) {
  258. this.onStartListen = onStartListen;
  259. return this;
  260. }
  261. public OnProgressListen getOnProgressListen() {
  262. return onProgressListen;
  263. }
  264. public Task setOnProgressListen(OnProgressListen onProgressListen) {
  265. this.onProgressListen = onProgressListen;
  266. return this;
  267. }
  268. public OnFinishListen getOnFinishListen() {
  269. return onFinishListen;
  270. }
  271. public Task setOnFinishListen(OnFinishListen onFinishListen) {
  272. this.onFinishListen = onFinishListen;
  273. return this;
  274. }
  275. public OnSystemStartListen getOnSystemStartListen() {
  276. return onSystemStartListen;
  277. }
  278. public OnSystemFinishListen getOnSystemFinishListen() {
  279. return onSystemFinishListen;
  280. }
  281. public void setOnSystemFinishListen(
  282. OnSystemFinishListen onSystemFinishListen) {
  283. this.onSystemFinishListen = onSystemFinishListen;
  284. }
  285. public int getTaskID() {
  286. return taskID;
  287. }
  288. public Task setTaskID(int taskID) {
  289. this.taskID = taskID;
  290. return this;
  291. }
  292. public Object getResult() {
  293. return result;
  294. }
  295. public int getTryAgainCount() {
  296. return tryAgainCount;
  297. }
  298. public Task setTryAgainCount(int tryAgainCount) {
  299. this.tryAgainCount = tryAgainCount;
  300. return this;
  301. }
  302. public int getTryAgainTime() {
  303. return tryAgainTime;
  304. }
  305. private Task setTryAgainTime(int tryAgainTime) {
  306. this.tryAgainTime = tryAgainTime;
  307. return this;
  308. }
  309. public Object  put(String key,Object value) {
  310. if(dataMap==null)
  311. {
  312. dataMap=new HashMap<String, Object>();
  313. }
  314. return dataMap.put(key, value);
  315. }
  316. public Object  get(String key,Object value) {
  317. if(dataMap==null)
  318. {
  319. dataMap=new HashMap<String, Object>();
  320. }
  321. return dataMap.get(key);
  322. }
  323. }
  1. package demo2;
  2. import java.util.AbstractCollection;
  3. import java.util.ArrayList;
  4. import java.util.Collections;
  5. import java.util.Iterator;
  6. import java.util.LinkedList;
  7. import java.util.List;
  8. import java.util.Queue;
  9. import java.util.Random;
  10. import demo2.Task.OnSystemFinishListen;
  11. import demo2.Task.TaskStatus;
  12. public class TaskQueue implements Runnable, OnSystemFinishListen {
  13. static String debug = "TaskQueue";
  14. @SuppressWarnings("unchecked")
  15. // 在等待的任务队列
  16. static LinkedList<Task> tasks_wait = new LinkedList<Task>();
  17. public static class TaskQueueExpection extends Exception{
  18. TaskQueueExpection(String detailMessage) {
  19. super(detailMessage);
  20. // TODO Auto-generated constructor stub
  21. }
  22. };
  23. // 正在执行的任务
  24. static ArrayList<Task> tasks_running = new ArrayList<Task>();
  25. // 是否持续运行
  26. public static boolean isRun=true;
  27. // runnable保证线程安全
  28. private static TaskQueue runnable = new TaskQueue();;
  29. // 最大线程数
  30. static int ThreadMaxNum = 1;
  31. public static TaskQueue getRunnable() {
  32. return runnable;
  33. }
  34. // 如果队列线程为空或者停止则重新开启
  35. public static void serivesRun() {
  36. // TODO Auto-generated method stub
  37. boolean isCanSeriver=false;
  38. synchronized (tasks_running) {
  39. isCanSeriver=tasks_running.size() < ThreadMaxNum;
  40. }
  41. runnable.run();
  42. }
  43. //获取正在执行的任务数
  44. public static int getRunningTaskCount() {
  45. synchronized (TaskQueue.tasks_running) {
  46. return TaskQueue.tasks_running.size();
  47. }
  48. }
  49. //设置最大任务数
  50. public static void setThreadMaxNum(int num) {
  51. TaskQueue.ThreadMaxNum = num<1?1:num>100?100:num;
  52. }
  53. // 线程锁 如果等待队列的任务数不为空,并且当前线程数字少于最大线程数
  54. public static boolean taskRun() {
  55. synchronized (tasks_wait) {
  56. synchronized (tasks_running) {
  57. return !tasks_wait.isEmpty()
  58. && tasks_running.size() < ThreadMaxNum;
  59. }
  60. }
  61. }
  62. //开启新线程
  63. public void run() {
  64. // 线程锁 如果等待队列的任务数不为空,并且当前线程数字少于最大线程数
  65. Task newTask;
  66. while((newTask=getWaittingTask())!=null)
  67. {
  68. System.err.println("开启新线程处理一个新任务,ID:"+newTask.getTaskID());
  69. newTask.setOnSystemFinishListen(runnable);
  70. newTask.threadRun();
  71. newTask=null;
  72. }
  73. }
  74. //递归 避免新开线程   唤醒等待中的任务 但此方案会造成java.lang.StackOverflowError
  75. void notifyWaitingTask()
  76. {
  77. Task newTask;
  78. while((newTask=getWaittingTask())!=null)
  79. {
  80. System.err.println("唤醒旧线程处理一个新任务,ID:"+newTask.getTaskID());
  81. newTask.setOnSystemFinishListen(runnable);
  82. newTask.run();
  83. newTask=null;
  84. }
  85. }
  86. private  Task getWaittingTask()
  87. {
  88. Task t=null;
  89. //测试
  90. while (isRun && taskRun()) {
  91. // 添加带执行中动态数组中
  92. synchronized (tasks_wait) {
  93. // 从等待任务的队列中获取并移除此列表的头(第一个元素)
  94. t = tasks_wait.poll();
  95. // 如果h为空则从队列重新取对象或者任务绑定的状态变化了
  96. if (t == null || t.status == TaskStatus.without) {
  97. System.out.println("任务取消 编号" + t!=null?String.valueOf(t.getTaskID()):"空任务");
  98. continue;
  99. }
  100. }
  101. synchronized (tasks_running) {
  102. tasks_running.add(t);
  103. }
  104. System.out.println( "正在执行任务数" + tasks_running.size() + "/上限"
  105. + ThreadMaxNum);
  106. return t;
  107. }
  108. return t;
  109. }
  110. @Override
  111. public void OnSystemFinish(Task t, Object data) {
  112. // TODO Auto-generated method stub
  113. synchronized (tasks_running) {
  114. // 从处理中的动态数组中移除此任务
  115. tasks_running.remove(t);
  116. System.out.println( "执行队列中移除任务taskid=" + t.taskID);
  117. // 通知执行后续未处理的任务
  118. System.out.println("正在执行任务数" + tasks_running.size() + "/上限"
  119. + ThreadMaxNum);
  120. // 移除此名字映射
  121. if (t.getSingletonName() != null) {
  122. Task.getNameTask().remove(t.getSingletonName());
  123. }
  124. }
  125. }
  126. }

Demo代码下载地址

版权声明:本文为博主原创文章,未经博主允许不得转载。

Java Design Demo -简单的队列-异步多任务队列(java android)的更多相关文章

  1. 夯实Java基础系列17:一文搞懂Java多线程使用方式、实现原理以及常见面试题

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...

  2. celery 分布式异步任务框架(celery简单使用、celery多任务结构、celery定时任务、celery计划任务、celery在Django项目中使用Python脚本调用Django环境)

    一.celery简介: Celery 是一个强大的 分布式任务队列 的 异步处理框架,它可以让任务的执行完全脱离主程序,甚至可以被分配到其他主机上运行.我们通常使用它来实现异步任务(async tas ...

  3. kafka 简单安装以及java小demo

    文章目录 第1步,下载解压 kafka: 第2步,运行 kafka: 第3步,创建topic 第4步,生产者发送消息 第5步,消费者接收消息 使用 java 客户端 kafka 0.8.0版本demo ...

  4. java网络爬虫----------简单抓取慕课网首页数据

    © 版权声明:本文为博主原创文章,转载请注明出处 一.分析 1.目标:抓取慕课网首页推荐课程的名称和描述信息 2.分析:浏览器F12分析得到,推荐课程的名称都放在class="course- ...

  5. 从Java future 到 Guava ListenableFuture实现异步调用

    从Java future 到 Guava ListenableFuture实现异步调用 置顶 2016年04月24日 09:11:14 皮斯特劳沃 阅读数:17570 标签: java异步调用线程非阻 ...

  6. 八.利用springAMQP实现异步消息队列的日志管理

    经过前段时间的学习和铺垫,已经对spring amqp有了大概的了解.俗话说学以致用,今天就利用springAMQP来完成一个日志管理模块.大概的需求是这样的:系统中有很多地方需要记录操作日志,比如登 ...

  7. java数据结构和算法03(队列和优先级队列)

    什么是队列呢?其实队列跟栈很像,我们可以把栈的底部给弄开,这样数据就可以从下面漏出来了,我们就从下面拿就好了. 可以看到队列是新进先出,就跟我们显示生活中的排队一样,买火车票,飞机票等一样,先去的肯定 ...

  8. 异步分布式队列Celery

    异步分布式队列Celery 转载地址 Celery 是什么? 官网 Celery 是一个由 Python 编写的简单.灵活.可靠的用来处理大量信息的分布式系统,它同时提供操作和维护分布式系统所需的工具 ...

  9. java并发包提供的三种常用并发队列实现

    java并发包中提供了三个常用的并发队列实现,分别是:ConcurrentLinkedQueue.LinkedBlockingQueue和ArrayBlockingQueue. ConcurrentL ...

随机推荐

  1. QDebug &operator<<出错(根据QString来找,是不得要领的,而是应该根据QString所在的对象来思考)

    程序运行后,总是崩溃在这个地方:inline QDebug &operator<<(const QString & t) 我应该用什么办法找出是哪个QString出了问题呢 ...

  2. 设计模式 ( 十九 ) 模板方法模式Template method(类行为型)

      设计模式 ( 十九 ) 模板方法模式Template method(类行为型) 1.概述 在面向对象开发过程中,通常我们会遇到这样的一个问题:我们知道一个算法所需的关键步骤,并确定了这些步骤的执行 ...

  3. C语言之基本算法09—各位全是a的数列之和

    /* ================================================================== 题目:数列为a,aa,aaa,--.求a+aa+aaa+-- ...

  4. 在ibatis下匹配特殊手机号码(oracle数据库)

    <isNotNull prepend="AND" property="endNumber"> <isNotEmpty property=&qu ...

  5. 网页制作之html基础学习5-background-position用法

    我们知道在用图片作为背景的时候,css要这样写,以div容器举例子,也可以是body.td.p等的背景,道理一样. 代码: div{ background:#FFF url(image) no-rep ...

  6. eclipse No Default Proposals 无提示

    链接地址:http://blog.csdn.net/rogerjava/article/details/5689785 今天特抑郁,早上开机后发现eclipse的代码提示功能不好使了,Alt+/ 这么 ...

  7. BZOJ 2318: Spoj4060 game with probability Problem( 概率dp )

    概率dp... http://blog.csdn.net/Vmurder/article/details/46467899 ( from : [辗转山河弋流歌 by 空灰冰魂] ) 这个讲得很好 , ...

  8. 07-IOSCore - CoreData补充、音频视频

    xml被plist取代了  数据库被coredata取代了 一.Core Data 高级补充 1. Core Data 本质是什么?操作数据库的数据 ORM Object Relationship M ...

  9. c++怎样让返回对象的函数不调用拷贝构造函数

    我们知道拷贝构造函数有两种“默默”的方式被调用 1. 想函数传入 值参数 2. 函数返回 值类型 今天我们讨论函数返回值类型的情况. 得到结论是 1. 当对象有拷贝构造函数(系统为我们生成.或者我们自 ...

  10. 通过cmd命令安装、卸载、启动和停止Windows Service(InstallUtil.exe)-大壮他哥

    步骤: 1.运行--〉cmd:打开cmd命令框 2.在命令行里定位到InstallUtil.exe所在的位置 InstallUtil.exe 默认的安装位置是在C:/Windows/Microsoft ...