疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

java多线程例子学习笔记


 

  java在2007年的时候编写过多线程爬虫,当时对多线程的理解仅仅限于可以同时并发任务,对于多线程之间的调度,完全没有理解。所以后来这的多线程的应用仅仅限于只能多线程并发任务。其实一切在线程中都可以被监控。

  看下面的列子,我们来理解多线程之间如何进行控制的。

  代码如下

  package com.javaer.thread;

  public class PrintABC {

  public static Boolean isThreadA = true;

  public static Boolean isThreadB = false;

  public static Boolean isThreadC = false;

  public static void main(String[] args) {

  final PrintABC abc = new PrintABC();

  new Thread(new Runnable() {

  public void run() {

  for (int i = 0; i < 10; i++) {

  synchronized (abc) {

  while (!isThreadA) {

  try {

  abc.wait();

  } catch (InterruptedException e) {

  // TODO Auto-generated catch block

  e.printStackTrace();

  }

  }

  System.out.print("A");

  isThreadA = false;

  isThreadB = true;

  isThreadC = false;

  abc.notifyAll();

  }

  }

  }

  }).start();

  new Thread(new Runnable() {

  public void run() {

  for (int i = 0; i < 10; i++) {

  synchronized (abc) {

  while (!isThreadB) {

  try {

  abc.wait();

  } catch (InterruptedException e) {

  // TODO Auto-generated catch block

  e.printStackTrace();

  }

  }

  System.out.print("B");

  isThreadA = false;

  isThreadB = false;

  isThreadC = true;

  abc.notifyAll();

  }

  }

  }

  }).start();

  new Thread(new Runnable() {

  public void run() {

  for (int i = 0; i < 10; i++) {

  synchronized (abc) {

  while (!isThreadC) {

  try {

  abc.wait();

  } catch (InterruptedException e) {

  // TODO Auto-generated catch block

  e.printStackTrace();

  }

  }

  System.out.print("C");

  isThreadA = true;

  isThreadB = false;

  isThreadC = false;

  abc.notifyAll();

  }

  }

  }

  }).start();

  }

  }

  输出结果如下 :ABCABCABCABCABC

  思路:解题思路大概是这样的,开启三个线程,每个线程一次打印一个字母,并且按照一定的顺序打印,当打印A的时候,其他线程处于阻塞状态,打印完A以后,将线程解锁,让打印B的那个线程开启,其他线程处于阻塞状态,同理打印C的时候,阻塞其他线程,这三个线程顺序循环,就达到顺序多次打印ABC的目的了。

  这道题看似思路简单,其实主要需要用到wait()方法和notify()方法,还有关键字synchronized,只有充分理解了这些,才能解出这道题。下面我有必要讲解一下这两个方法,还有关键字synchronized。

  多线程并行下载的核心特点就是分段,并行下载。

  比如一个文件200M,分5个线程,那么就给砍成5份,分别同时下就好了。速度当然比一点点下载来的要快的多。

  代码如下

  package com.javaer.examples.file;

  import java.io.File;

  import java.io.FileWriter;

  import java.io.IOException;

  import java.io.InputStream;

  import java.io.RandomAccessFile;

  import java.net.HttpURLConnection;

  import java.net.MalformedURLException;

  import java.net.URL;

  import java.net.URLConnection;

  public class MyMutilDown {

  /**

  * 单线程的远程下载

  */

  public void SingleDown(String filePath, String url) {

  try {

  // 要写入的文件

  File file = new File(filePath + getFileExtName(url));

  FileWriter fWriter = new FileWriter(file);

  URL ul = new URL(url);

  URLConnection conn = ul.openConnection();

  conn.setConnectTimeout(2000);// 请求超时时间

  // int len = conn.getContentLength();

  InputStream in = conn.getInputStream();

  // byte[] by = new byte[1024];

  int temp = 0;

  while ((temp = in.read()) != -1) {

  System.out.println(temp);

  fWriter.write(temp);

  }

  fWriter.close();

  in.close();

  } catch (MalformedURLException e) {

  // TODO Auto-generated catch block

  e.printStackTrace();

  } catch (IOException e) {

  // TODO Auto-generated catch block

  e.printStackTrace();

  }

  }

  /**

  * 文件后缀名

  *

  * @param path

  * @return

  */

  public String getFileExtName(String path) {

  return path.substring(path.lastIndexOf("."));

  }

  /**

  * 测试多线程

  *

  * @param filePath

  * 文件保存路径

  * @param url

  * url

  * @param tnum

  * 线程数量

  */

  public void MutiDown(String filePath, String url, int tnum) {

  try {

  // 要写入的文件

  final File file = new File(filePath + getFileExtName(url));

  System.out.println(file.getAbsolutePath());

  RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");// 建立随机访问

  final URL ul = new URL(url);

  HttpURLConnection conn = (HttpURLConnection) ul.openConnection();

  conn.setConnectTimeout(2000);// 请求超时时间

  conn.setRequestMethod("GET");

  int len = conn.getContentLength();// 文件长度

  accessFile.setLength(len);

  accessFile.close();

  final int block = (len + tnum - 1) / tnum;// 每个线程下载的快大小

  for (int i = 0; i < tnum; i++) {

  final int a = i;

  new Thread(new Runnable() {

  int start = block * a;// 开始位置

  int end = block * (a + 1) - 1;// 结束位置

  @Override

  public void run() {

  HttpURLConnection conn2 = null;

  RandomAccessFile accessFile2 = null;

  InputStream in = null;

  try {

  conn2 = (HttpURLConnection) ul.openConnection();

  conn2.setConnectTimeout(2000);// 请求超时时间

  conn2.setRequestMethod("GET");

  // TODO Auto-generated method stub

  conn2.setRequestProperty("Range", "bytes=" + start

  + "-" + end + "");// 设置一般请求属性 范围

  in = conn2.getInputStream();

  byte[] data = new byte[1024];

  int len = 0;

  accessFile2 = new RandomAccessFile(file, "rwd");

  accessFile2.seek(start);

  while ((len = in.read(data)) != -1) {

  System.out.println(a + "/" + len);

  accessFile2.write(data, 0, len);//并发写入

  }

  System.out.println("线程:" + a + "下载完成!");

  } catch (IOException e1) {

  // TODO Auto-generated catch block

  e1.printStackTrace();

  } finally {

  try {

  accessFile2.close();

  in.close();

  } catch (IOException e) {

  // TODO Auto-generated catch block

  e.printStackTrace();

  }

  }

  }

  }).start();

  }

  } catch (MalformedURLException e) {

  // TODO Auto-generated catch block

  e.printStackTrace();

  } catch (IOException e) {

  // TODO Auto-generated catch block

  e.printStackTrace();

  }

  }

  /**

  * @param args

  * @throws IOException

  */

  public static void main(String[] args) throws IOException {

  MyMutilDown mydown = new MyMutilDown();

  String path = "openx-220080603.rar";

  // mydown.SingleDown("/", path);

  mydown.MutiDown("/bbc", path, 3);

  }

  }