=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类,利用多线程实现爬虫下载,提高运行效率。
`