工作中遇到的问题,记录下解决的思路

问题:

   对磁盘进行碎片化测试(比如说,磁盘空间是16G),从64K开始写文件,写满后删除一半,然后写32K 的数据,写满后删除一半。。。直到4K写满删除一般算是结束

第一阶段:

  使用单独的一个线程进行操作,先写数据,然后删除数据,用循环控制跳出

代码

public class Task extends Thread{public void run() {int size = 64;while(size >=4){write(size);delete();size /= 2;}}private void write(int size){//省略具体的写数据方法,判断是否写满
    }private void delete(){//省略删除的方法
    }
}

View Code

上述的代码已经实现了功能,但是如果空间很大,怎么半?一个线程写的也太慢了,如何提高效率,写入的速度?

办法就是使用多线程,多个线程同时写,肯定能提升不小的效率

第二阶段:

  使用多个线程进行操作,代码和第一阶段的代码没有变化,共同写同一个磁盘就行

然后出现了新的问题,多线程操作,到最后肯定会出现剩余的磁盘空间就够一个线程使用(假如是线程A ),其他线程已经写完了该阶段的内容(假如是线程B,C,D),开始执行删除操作了,此时,这4个线程有的在写入数据,有的在删除数据,会导致线程A一直读到有剩余空间可以写入(因为其他线程在删除文件,腾出新的空间),这样到最后4K的时候,就出现了A 线程还在写,其他的线程都已经停止好久了。又浪费了好多时间。

  如何解决呢?我想到了使用线程的同步,A线程写完了就等其他线程,等到所有的线程都写完了,大家一起开始删除,等到大家都删除完成了,再一起开始下一个阶段的写入

  那该如何等待呢?

  我用了Object类的wait()和notifyAll()方法。

第三阶段:

  使用同步解决其他线程结束,就剩余一个线程写的问题,进一步的提高效率

代码

import java.util.HashMap;
import java.util.Map;/*** 状态信息类*/
public class Status {private int finishCount = 0;private int threadCount = 0;// 存储每个线程的状态private Map<Integer, Boolean> maps;public Status(int threadCount) {this.maps = new HashMap<Integer, Boolean>();this.threadCount = threadCount;}//更新当前线程是否在等待状态,status = true表示已经在等待了public synchronized void setStatus(int threadIndex, boolean statu) {maps.put(threadIndex, statu);}public boolean getStatus() {boolean result = true;for (Map.Entry<Integer, Boolean> entry : maps.entrySet()) {result = result && entry.getValue();}return result;}// 更新已经完成的线程个数(全部各个阶段执行完调用)public synchronized void updateFinishCount() {this.finishCount += 1;}public int getFinishCount() {return finishCount;}
}

View Code

/*** 观察线程*/
public class Watcher extends Thread{private int threadCount = 0;private Status status;public Watcher(Status status,int threadCount ) {this.status = status;this.threadCount = threadCount;}public void run() {while(true){//检查是否所有status对象上的线程是否都在等待if(status.getStatus()){status.notifyAll();}//检查是否所有线程全部执行完成if(status.getFinishCount() == threadCount){break;}}}
}

View Code

/*** 具体执行任务的线程*/
public class Task extends Thread{private Status status;private int index;public Task(Status status,int index) {this.status = status;this.index =index;}public void run() {int size = 64;while(size >=4){write(size);synchronized (status) {status.setStatus(index, true);//设置为等待状态try {status.wait();} catch (InterruptedException e) {e.printStackTrace();}}status.setStatus(index, false);//取消等待状态
            delete();synchronized (status) {status.setStatus(index, true);//设置为等待状态try {status.wait();} catch (InterruptedException e) {e.printStackTrace();}}status.setStatus(index, false);//取消等待状态size /= 2;}}private void write(int size){//省略具体的写数据方法,判断是否写满
    }private void delete(){//省略删除的方法
    }
}

View Code

现在看起来是完美了,但是实际的运行过程中,会发现,真的没有控制住线程的同步,还是出现了之前的第二阶段的问题,有一个线程比其他线程慢,而且出现了一个线程没有按照依次递减的顺序执行的古怪情况,我想应该是没有真正的同步造成的。之后又去查找资料,发现Java提供了一个类,就像是为这种情况量身定做的。它就是 CyclicBarrier  ,它自己维护了一个计数器,每当调用一次await()方法,就会阻塞当前的线程,并且计数器减一,计数器的值来源于构造方法,计数器为0的时候,就解除阻塞,更好的是,当计数器为0时,再调用await()方法的时候,会将计数器变成初始值减一,重新开始一个循环。

第四阶段:

  

*** 具体执行任务的线程*/
public class Task extends Thread {private CyclicBarrier cyclicBarrier;public Task(CyclicBarrier cyclicBarrier) {this.cyclicBarrier = cyclicBarrier;}public void run() {int size = 64;while (size >= 4) {write(size);try {cyclicBarrier.await();} catch (InterruptedException e) {e.printStackTrace();} catch (BrokenBarrierException e) {//捕获到该异常的话,表示这个线程不用等待了,需要处理一下,唤醒其他阻塞的线程
                e.printStackTrace();}delete();try {cyclicBarrier.await();} catch (InterruptedException e) {e.printStackTrace();} catch (BrokenBarrierException e) {e.printStackTrace();}size /= 2;}}private void write(int size) {// 省略具体的写数据方法,判断是否写满
    }private void delete() {// 省略删除的方法
    }
}

View Code

测试的代码

public class Test {private static final int THREAD_COUNT = 4;public static void main(String[] args) {CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT);for(int i=0;i<THREAD_COUNT;i++){new Task(barrier).start();}}
}

View Code

  

转载于:https://www.cnblogs.com/android-lol/p/6891872.html

Java 多线程使用相关推荐

  1. Java 多线程的基本方式

    Java 多线程的基本方式 基础实现两种方式: 通过实现Callable 接口方式(可得到返回值):

  2. Java多线程读取本地照片为二进制流,并根据系统核数动态确定线程数

    Java多线程读取图片内容并返回 1. ExecutorService线程池 2. 效率截图 3. 源码 1. ExecutorService线程池 ExecutorService线程池,并可根据系统 ...

  3. Java多线程,Thread,Runnable,Callable Task,Future<Task>,CompletionService

    一.Java多线程的方法 1. 继承 Thread 2. 实现 Runnable 3. 实现 Callable 可以有返回值 package com.test;import java.util.Arr ...

  4. 【收藏】Java多线程/并发编程大合集

    (一).[Java并发编程]并发编程大合集-兰亭风雨    [Java并发编程]实现多线程的两种方法    [Java并发编程]线程的中断    [Java并发编程]正确挂起.恢复.终止线程    [ ...

  5. 40个Java多线程问题总结

    (转) 这篇文章作者写的真是不错 40个问题汇总 1.多线程有什么用? 一个可能在很多人看来很扯淡的一个问题:我会用多线程就好了,还管它有什么用?在我看来,这个回答更扯淡.所谓"知其然知其所 ...

  6. Java多线程编程实战:模拟大量数据同步

    背景 最近对于 Java 多线程做了一段时间的学习,笔者一直认为,学习东西就是要应用到实际的业务需求中的.否则要么无法深入理解,要么硬生生地套用技术只是达到炫技的效果. 不过笔者仍旧认为自己对于多线程 ...

  7. Java多线程学习处理高并发问题

    在程序的应用程序中,用户或请求的数量达到一定数量,并且无法避免并发请求.由于对接口的每次调用都必须在返回时终止,因此,如果接口的业务相对复杂,则可能会有多个用户.调用接口时,该用户将冻结. 以下内容将 ...

  8. Java多线程常见面试题及答案汇总1000道(春招+秋招+社招)

    Java多线程面试题以及答案整理[最新版]Java多线程高级面试题大全(2021版),发现网上很多Java多线程面试题都没有答案,所以花了很长时间搜集,本套Java多线程面试题大全,汇总了大量经典的J ...

  9. java多线程编程01---------基本概念

    一. java多线程编程基本概念--------基本概念 java多线程可以说是java基础中相对较难的部分,尤其是对于小白,次一系列文章的将会对多线程编程及其原理进行介绍,希望对正在多线程中碰壁的小 ...

  10. Java多线程的同步机制(synchronized)

    一段synchronized的代码被一个线程执行之前,他要先拿到执行这段代码的权限,在 java里边就是拿到某个同步对象的锁(一个对象只有一把锁): 如果这个时候同步对象的锁被其他线程拿走了,他(这个 ...

最新文章

  1. javaScript的调试(二)
  2. java里面快速排序_Java:快速排序
  3. Excel更正错误#NAME?
  4. 在代码中使用SqlCommand对象
  5. gitlab mysql 配置_gitlab的安装与修改端口配置
  6. Android Studio :1、连接手机调试(超级详细;附带连接测试录像);2、点击Button按钮,显示Toast中的内容
  7. Linux vim 快捷键
  8. Service rootservice does not have a SELinux domain defined
  9. 【LeetCode笔记】416. 分割等和子集(Java、动态规划、背包问题、滚动数组)
  10. git上传新项目到服务器_springboot项目打包上传至阿里云服务器
  11. mysql+centos7+主从复制
  12. MicroDicom viewer(Dicom格式看图软件) v3.4.7官方版
  13. 思维模型 帕累托法则
  14. C语言简单实现14个例题(谭浩强第四版)
  15. 认知升级:什么才是真正的高情商?
  16. 用ZBrush和Maya建模雕刻一位灵长类动物飞行员 你必须要了解角色是不是有甲方客户的创作需求或是基于其他画师的概念。
  17. 鼠标坏了怎么用键盘操作鼠标
  18. oracle数据误删怎么恢复,Oracle数据误删了怎么恢复
  19. JS逆向 --- 易盾有感滑块
  20. 计算机视觉领域推荐期刊和会议评分标准

热门文章

  1. 关于wcf三大工具的使用(wsdl.exe svcutil.exe disco.exe)
  2. 我的Android 4 学习系列
  3. Oracle在线重定义
  4. HTTP Continuation or non-HTTP traffic
  5. ProtoBuf 简单测试
  6. Oracle配置监听和连接,已经一些比较容易混淆的相关概念
  7. servlet之servletResponse
  8. OSChina 周一乱弹 —— 抱着漂亮袜子就亲了一口
  9. 自动化部署之gitlab备份和恢复
  10. thinkphp集成系列之phpmailer批量发送邮件