`

Java线程学习

    博客分类:
  • Java
阅读更多
从线程中取得信息
轮询 主程序无限循环,从子线程取得返回值,直到子线程执行完毕(返回值不为0)
public class ReturnThread extends Thread {
  private int time;
  private int result;

  public ReturnThread(int time) {
    this.time = time;
  }

  public void run() {
    try {
      TimeUnit.SECONDS.sleep(time);
    } catch (InterruptedException e) {
      throw new RuntimeException(e);
    }
    result = time;
  }

  public int getResult() {
    return result;
  }
}

public class ReturnThreadShell {

  public static void main(String[] args) {
    Random r = new Random(47);
    ReturnThread[] threads = new ReturnThread[5];
    for (int i = 0; i < 5; i++) {
      int time = r.nextInt(10);
      ReturnThread thread = new ReturnThread(time);
      threads[i] = thread;
      thread.start();
    }
    for (int i = 0; i < threads.length; i++) {
      while (true) {
        int rslt = threads[i].getResult();
        if (rslt != 0) {
          System.out.println("thread " + i + "
              is finish. return value is " + rslt);
          break;
        }
      }
    }
  }
}
//thread 0 is finish. return value is 8
//thread 1 is finish. return value is 5
//thread 2 is finish. return value is 3
//thread 3 is finish. return value is 1
//thread 4 is finish. return value is 1


回调 子线程执行完成后,调用主线程的方法
public class CallbackThread extends Thread {
  private int time;
  private CallbackThreadShell callback;

  public CallbackThread(int time, CallbackThreadShell callback) {
    this.time = time;
    this.callback = callback;
  }

  public void run() {
    try {
      TimeUnit.SECONDS.sleep(time);
    } catch (InterruptedException e) {
      throw new RuntimeException(e);
    }
    callback.receiveResult(time, callback.threadId);
  }
}

public class CallbackThreadShell {
  private int time;
  protected int threadId;

  public CallbackThreadShell(int time, int threadId) {
    this.time = time;
    this.threadId = threadId;
  }

  public void runThread() {
    CallbackThread thread = new CallbackThread(time, this);
    thread.start();
  }

  public void receiveResult(int result, int threadId) {
    System.out.println("thread " + threadId 
        + " is finish. return value is " + result);
  }

  public static void main(String[] args) {
    Random r = new Random(47);
    for (int i = 0; i < 5; i++) {
      CallbackThreadShell shell = new CallbackThreadShell(r.nextInt(10), i);
      shell.runThread();
    }
  }
}
//thread 3 is finish. return value is 1
//thread 4 is finish. return value is 1
//thread 2 is finish. return value is 3
//thread 1 is finish. return value is 5
//thread 0 is finish. return value is 8


同步
同步块 java无法阻止其他所有线程使用共享资源的方法,他只能防止对同一对象同步的其他线程使用该共享资源
同步方法

同步的替代方法
1 使用局部变量代替类变量
2 简单类型的方法参数是安全的,因为java通过值传递不是引用传递参数,对象类型的方法参数,如果是final的,也是线程安全的
3 将非线程安全的类,作为一个线程安全的类的私有字段


死锁
防止死锁要避免不必要的线程同步!!


线程调度
抢占与协作 抢占式线程调度器确定线程公平的享用CPU时间,然后暂停此线程,将CPU控制权交给另外的线程。(饥饿问题很难发现)
协作式线程调度器会在CPU控制权交给其他线程前,等待运行中的线程自己暂停。

为了有利于其他线程,一个线程有以下方式可以暂停或指示准备暂停
阻塞 I/O时阻塞、同步其他对象是阻塞。当线程必须停下来,等待他没有的资源,就发生了阻塞。此时线程不会释放任何线程已经拥有的锁。

放弃 Thread.yield()。线程愿意暂停,让其他同等优先级的线程有机会运行

休眠 Thread.sleep()。线程不管有没有其他线程准备运行都会暂停
调用休眠线程的interrupt()方法,可以唤醒该线程,这是线程与Thread对象之间的重要区别之一(线程休眠中,仍然可以调用方法与之交互)唤醒会让休眠线程得到一个InterruptedException
一个通过InterruptedException结束线程的例子
public void run(){
  while(true){
    try{ Thread.sleep(300000);
    }catch(InterruptedException e){ break;}}}


连接线程 Thread.join()。一个线程需要另一个线程的结果,即主线程(调用join()方法的线程)等待被连接的线程(join()方法被调用的线程)结束.

等待一个对象  Object.wait()。等待用于暂停执行,直到一个对象或资源达到某种状态,连接则用于暂停执行,知道一个线程结束。在等待时,他会释放此对象的锁并暂停(但不是他拥有的任何其他对象的锁),直到得到其他线程通知notify()或时间到期、线程被中断interrupt()。
一旦等待线程得到通知,他就试图重新获得所等待对象的锁,如果成功,就继续执行紧接着wait()调用后的语句,如果失败,他就会阻塞与此对象,直到可以得到锁。
while (pool.isEmpty()) {
  try {
    pool.wait();
    // 收到通知时,停止等待,执行之后的内容
    // 必须pool.isEmpty(),因为我们不知道处理完成后,pool中是否仍有内容
  } catch (InterruptedException ex) {}
}
// 取得一个连接,处理这一项。。。
connection = (Socket) pool.remove(0);

synchronized (pool) {
  pool.add(pool.size(), request);
  pool.notifyAll();
}

基于优先级的抢占 setPriority()方法

结束 当run()方法返回时,线程将销毁,其他线程就可以接管CPU。



线程池
实现方法
1 第一次创建池时,分配固定数量的线程,当池为空时,所有线程都在等待,当向池添加一项任务时,所有等待的线程都得到通知。当一个线程结束其分配的任务时,它再回到池中等待新任务。
2 将线程本身放在池中,让主程序从池中取出线程,为其分配任务。每个线程结束后返回池中。


一个例子,多线程压缩文件

public class GZipThread extends Thread {

  private List pool;
  private static int filesCompressed = 0;

  public GZipThread(List pool) {
    this.pool = pool;
  }

  private static synchronized void incrementFilesCompressed() {
    filesCompressed++;
    System.out.println(filesCompressed);
  }

  public void run() {
    while (filesCompressed != GZipAllFiles.getNumberOfFilesToBeCompressed()) {
      File input = null;
      synchronized (pool) {
        while (pool.isEmpty()) {
          if (filesCompressed == GZipAllFiles.getNumberOfFilesToBeCompressed()) {
            System.out.println("Thread ending");
            return;
          }
          try {
            pool.wait();
          } catch (InterruptedException ex) {
          }
        }
        input = (File) pool.remove(pool.size() - 1);
        incrementFilesCompressed();
      }
      // don't compress an already compressed file
      if (!input.getName().endsWith(".gz")) {
        try {
          InputStream in = new FileInputStream(input);
          in = new BufferedInputStream(in);
          File output = new File(input.getParent(), input.getName() + ".gz");
          if (!output.exists()) { // Don't overwrite an existing file
            OutputStream out = new FileOutputStream(output);
            out = new GZIPOutputStream(out);
            out = new BufferedOutputStream(out);
            int b;
            while ((b = in.read()) != -1)
              out.write(b);
            out.flush();
            out.close();
            in.close();
          }
        } catch (IOException ex) {
          System.err.println(ex);
        }
      } // end if
    } // end while
  } // end run
} // end ZipThread

public class GZipAllFiles {

  public final static int THREAD_COUNT = 4;
  private static int filesToBeCompressed = -1;

  public static void main(String[] args) {
    Vector pool = new Vector();
    GZipThread[] threads = new GZipThread[THREAD_COUNT];
    for (int i = 0; i < threads.length; i++) {
      threads[i] = new GZipThread(pool);
      threads[i].start();
    }
    int totalFiles = 0;
    for (int i = 0; i < args.length; i++) {
      File f = new File(args[i]);
      if (f.exists()) {
        if (f.isDirectory()) {
          File[] files = f.listFiles();
          for (int j = 0; j < files.length; j++) {
            // 不递归文件夹
            if (!files[j].isDirectory()) {
              totalFiles++;
              synchronized (pool) {
                pool.add(0, files[j]);
                pool.notifyAll();
              }
            }
          }
        } else {
          totalFiles++;
          synchronized (pool) {
            pool.add(0, f);
            pool.notifyAll();
          }
        }
      } // end if
    } // end for
    filesToBeCompressed = totalFiles;
    System.out.println("totalFiles " + filesToBeCompressed);
    // 让等待线程知道,没有更多的文件会加到池中了
    // 如果需要压缩文件很少,有可能线程启动了,但没有需要压缩的文件
    for (int i = 0; i < threads.length; i++) {
      threads[i].interrupt();
    }
  }

  public static int getNumberOfFilesToBeCompressed() {
    return filesToBeCompressed;
  }

分享到:
评论

相关推荐

    Java线程 学习

    ### Java线程学习知识点 #### 一、Java线程概览 - **定义与作用**:线程是在程序中独立且并发执行的路径。在Java中,线程被设计为语言的一部分,而不是作为操作系统的底层工具。每个Java程序至少包含一个主线程,在...

    Java线程学习和总结

    在Java编程语言中,线程是程序执行的基本单元,它允许程序并发地...同时,"Java线程学习和总结.files"目录下的文件可能是与文章相关的辅助资料,例如代码示例或图片。建议结合这些资料一起学习,以获得更全面的知识。

    JAVA线程学习(源代码)

    本资源"JAVA线程学习(源代码)"提供了关于Java线程的源代码示例,帮助我们深入理解和实践线程的使用。 首先,我们要理解Java中的线程模型。Java线程由`java.lang.Thread`类或`java.util.concurrent.Executor`框架来...

    java线程学习笔记

    Java 线程学习笔记 Java 线程创建有两种方法: 1. 继承 Thread 类,重写 run 方法:通过继承 Thread 类并重写 run 方法来创建线程,这种方法可以使线程具有自己的执行逻辑。 2. 实现 Runnable 接口:通过实现 ...

    java线程学习教程

    ### Java线程学习教程知识点详解 #### 一、教程概览 - **适用人群**: 本教程主要面向那些已经熟练掌握了Java语言基本语法和应用,但对于多线程和并发编程经验较少的Java开发者。 - **目标**: 学习者通过本教程的...

    java线程学习一4

    在"java线程学习一4"这个主题中,我们将会深入探讨Java中的多线程概念,以及如何通过源码理解和使用相关工具进行线程管理。 首先,我们需要理解Java中的线程创建方式。Java提供了两种主要的线程创建方法:继承...

    java线程学习

    ### Java线程学习知识点 #### 一、线程的基本概念与创建 - **线程**:线程是程序执行流的最小单元。一个标准的Java应用程序至少有一个线程,即main线程。Java中线程的创建主要有两种方式:继承`Thread`类或者实现`...

    经典线程例子——Java线程学习指南

    通过学习以上知识点,初学者可以对Java线程有基本的理解,逐步掌握并发编程的核心技能。实践中的线程例子将有助于巩固理论知识,加深对线程工作原理的把握。在学习过程中,不断编写和调试多线程程序,是提升技能的...

    Java线程学习好资料

    本文将深入探讨Java线程的学习要点,帮助你提升在多线程环境下的编程能力。 首先,我们要明白线程的基本概念。线程是操作系统分配CPU时间的基本单元,一个进程中可以有多个线程同时执行任务,这使得程序可以在同一...

    java线程学习专题资料

    本专题资料聚焦于Java线程的学习,包括从基础到进阶的各种知识点。 1. **线程创建方式**:Java提供了两种创建线程的方式,一是通过继承Thread类,重写run()方法;二是实现Runnable接口,然后创建Thread对象并传入...

    JAVA多线程学习内容

    总的来说,Java多线程学习涵盖了线程的创建、同步、通信、调度以及异常处理等多个方面,深入理解和掌握这些知识点对于提升Java程序的性能和复杂性至关重要。通过阅读提供的"Java多线程.pdf"文档,你可以进一步了解和...

    多线程断点下载(java线程学习)

    java中多线程下载学习,又新增了断点的实现,可以实现暂停继续下载网络文件的功能

    Java多线程学习Java多线程学习Java多线程学习Java多线程学习.txt

    Java多线程学习Java多线程学习Java多线程学习Java多线程学习Java多线程学习Java多线程学习Java多线程学习Java多线程学习Java多线程学习Java多线程学习Java多线程学习Java多线程学习Java多线程学习Java多线程学习Java...

    Java线程学习很有用

    对于学习java线程的初学者是很有用的资料,让自己很快的上手,帮助自己学习很快的知识。。。

Global site tag (gtag.js) - Google Analytics