`

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;
  }

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics