=Start=
缘由:
学习整理一下Java中多线程编程的样例代码,方便以后使用。
正文:
参考解答:
一个线程完整的生命周期:
Java 提供了三种创建线程的方法:
- 通过实现 Runnable 接口;
- 通过继承 Thread 类本身;
- 通过 Callable 和 Future 创建线程。
代码样例:
package com.ixyzero.learn.misc; /** * Created by ixyzero.com on 2018/6/6. */ public class TestThread { public static void main(String args[]) { long t1 = System.currentTimeMillis(); System.out.println("Start @ " + t1); RunnableDemo R1 = new RunnableDemo("Thread-1"); R1.start(); RunnableDemo R2 = new RunnableDemo("Thread-2"); R2.start(); System.out.println("spend " + (System.currentTimeMillis() - t1) + " ms"); System.out.println("END @ " + System.currentTimeMillis()); } } /** * Java中创建线程的方法一: * 通过实现 Runnable 接口来创建线程 * 实现 run()/start() 方法 * 然后用 new Thread() 创建线程,再调用刚才的 start() 方法让它运行 */ class RunnableDemo implements Runnable { private Thread t; private String threadName; RunnableDemo( String name) { threadName = name; System.out.println("Creating " + threadName ); } public void run() { System.out.println("Running " + threadName ); try { for(int i = 4; i > 0; i--) { System.out.println("Thread: " + threadName + ", " + i + ", " + System.currentTimeMillis()); // 让线程睡眠一会 Thread.sleep(50); } }catch (InterruptedException e) { System.out.println("Thread " + threadName + " interrupted."); } System.out.println("Thread " + threadName + " exiting."); } public void start () { System.out.println("Starting " + threadName ); if (t == null) { t = new Thread (this, threadName); t.start (); } } }
&
package com.ixyzero.learn.misc; /** * Created by ixyzero.com on 2018/6/6. */ public class TestThread2 { public static void main(String args[]) { long t1 = System.currentTimeMillis(); System.out.println("Start @ " + t1); ThreadDemo T1 = new ThreadDemo( "Thread-1"); T1.start(); ThreadDemo T2 = new ThreadDemo( "Thread-2"); T2.start(); System.out.println("spend " + (System.currentTimeMillis() - t1) + " ms"); System.out.println("END @ " + System.currentTimeMillis()); } } /** * 通过继承 Thread 来创建线程 */ class ThreadDemo extends Thread { private Thread t; private String threadName; ThreadDemo( String name) { threadName = name; System.out.println("Creating " + threadName ); } public void run() { System.out.println("Running " + threadName ); try { for(int i = 4; i > 0; i--) { System.out.println("Thread: " + threadName + ", " + i + ", " + System.currentTimeMillis()); // 让线程睡眠一会 Thread.sleep(50); } }catch (InterruptedException e) { System.out.println("Thread " + threadName + " interrupted."); } System.out.println("Thread " + threadName + " exiting."); } public void start () { System.out.println("Starting " + threadName ); if (t == null) { t = new Thread (this, threadName); t.start (); } } }
&
单线程对比测试——new一个常规的class
package com.ixyzero.learn.misc; /** * Created by ixyzero.com on 2018/6/6. */ public class TestNewMethod { public static void main(String[] args){ MyThread myThread = new MyThread(); myThread.run(); while(true) { System.out.println("Main方法在运行"); } } } class MyThread{ public void run(){ while(true){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("MyThread 类的 run() 方法在运行"); } } }
上面这段代码的main()方法中的print语句将永远无法得到执行,因为该程序是一个单线程程序,当调用MyThread类的run()方法时,会遇到死循环,循环将一直进行。
下面这一段代码相比而言就是多了一个extends继承,就不会出现上面的那个情况:
package com.ixyzero.learn.misc; /** * Created by ixyzero.com on 2018/6/6. */ public class TestNewThreadMethod { public static void main(String[] args) { MyThread2 myThread2 = new MyThread2(); myThread2.start(); while (true) { System.out.println("main() method running..."); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } } class MyThread2 extends Thread{ public void run(){ while(true){ System.out.println("run() in MyThread2"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
多线程使用的注意事项:
- 有效利用多线程的关键是理解程序是并发执行而不是串行执行的。例如:程序中有两个子系统需要并发执行,这时候就需要利用多线程编程。
- 通过对多线程的使用,可以编写出非常高效的程序。不过请注意,如果你创建太多的线程,程序执行的效率实际上是降低了,而不是提升了。
- 请记住,上下文的切换开销也很重要,如果你创建了太多的线程,CPU 花费在上下文的切换的时间将多于执行程序的时间!
参考链接:
=END=
《 “Java多线程编程学习” 》 有 3 条评论
Java面试:投行的15个多线程和并发面试题
http://www.importnew.com/29562.html
https://dzone.com/articles/top-15-java-multithreading-concurrency-interview-q
`
1. 现在有线程 T1、T2 和 T3。你如何确保 T2 线程在 T1 之后执行,并且 T3 线程在 T2 之后执行?
2. Java 中新的 Lock 接口相对于同步代码块(synchronized block)有什么优势?如果让你实现一个高性能缓存,支持并发读取和单一写入,你如何保证数据完整性。
3. Java 中 wait 和 sleep 方法有什么区别?
4. 如何在 Java 中实现一个阻塞队列?
5. 如何在 Java 中编写代码解决生产者消费者问题?答案
6. 写一段死锁代码。你在 Java 中如何解决死锁?
7. 什么是原子操作?Java 中有哪些原子操作?
8. Java 中 volatile 关键字是什么?你如何使用它?它和 Java 中的同步方法有什么区别?
9. 什么是竞态条件?你如何发现并解决竞态条件?
10. 在 Java 中你如何转储线程(thread dump)?如何分析它?
11. 既然 start() 方法会调用 run() 方法,为什么我们调用 start() 方法,而不直接调用 run() 方法?
12. Java 中你如何唤醒阻塞线程?
13. Java 中 CyclicBarriar 和 CountdownLatch 有什么区别?
14. 什么是不可变类?它对于编写并发应用有何帮助?
15. 你在多线程环境中遇到的最多的问题是什么?你如何解决的?
`
Java代码实现多线程下载和断点续传
https://blog.csdn.net/qq_32101859/article/details/53177428
Java中实现多线程下载
https://blog.csdn.net/qq_19560943/article/details/68923446
Java爬虫之多线程下载IMDB中Top250电影的图片
https://segmentfault.com/a/1190000014169120
https://segmentfault.com/a/1190000014169769
`
爬虫思路:
利用Jsoup解析网页,得到电影图片的url和name
利用FileUtils.copyURLToFile()函数将图片下载到本地
总体的爬虫思路没有变化,只是在此基础上引入多线程。多线程的思路如下:
Java的每个任务类必须实现Runnable接口,因此,我们将新建ImageDownload类来实现Runnable接口。ImageDownload类的构造函数的参数有:url:网站的网址,dir:图片储存目录。并在run()方法中实现将网页中的图片下载到本地。
在主函数中,调用ImageDownload类,利用多线程实现爬虫下载,提高运行效率。
`