您的位置:首页 > 其它

人生只若如初见——初见线程

2017-07-29 10:16 239 查看
之前在学习多线程的时候,那个时候并没有掌握得很好,用一句话来形容就是“略懂一二”。近段时间,又重温了多线程,我却发现,多线程的内容涉及甚广,不仅仅针对单一程序,而且还涉及有关系统的性能等方面,今天决定重新来了解它,都说“人生只若如初见”,总觉得初见的时候我们是最好的,至此,已初见的态度重新学习多线程。

谈到线程,首先还是得从一些基本只是开始——————

线程和多线程

线程

所谓线程,使用官方的语言来说,能共享代码和数据空间的同一类程序,使用我自己的话来说,线程就如同一个系统中牵引着多个程序同时进行的“线”,(可能比喻得不太恰当,如谁有更形象的比喻,还请指正!),但是我们知道每个线程都有自己独立的的栈和程序计数器(PC),线程之间的切换开销相对于进程来说还是比较小的。那么,进程又是什么?没学过操作系统的人,可能不理解,其实,进程和线程如同双胞胎兄弟,从字面上区别,进程是指正在运行的程序,而线程范围似乎又包括进程,可是实质不以为然,进程可以是多种不同的程序。而线程是指同一类的程序,每一个进程都共享代码和数据空间,而线程是同一类线程共享代码和数据空间。从操作系统的角度来看,线程是CPU调度的最小单位,而进程是资源调度的最小单位。

多线程

那么多线程是什么呢?从字面上看,是多个线程共同运行的状态,其实,这里强调的是多个线程同时并发的状态,而我们所面临的就是如何去解决这并发的问题,要想探究得深入,那么首先,多线程必须理解得非常的得透彻。

理解

在了解线程是什么之后,需要明白一点,我们为什么要选择使用线程?很多人看来,使用线程能更大得提高效率,当然,也不能否认这点,多线程环境下,确实能够很大程度提高效率,但是凡事有利也有弊,有些时候,由于多线程创建和销毁过程是特别消耗内存的,因此这种情况下,效率不能提高反而降低性能。因此,对于多线程的使用,需要大量的经验来让我们学会如何掌控它。

线程的几种状态以及状态切换

线程状态是线程控制的基础。要想更好的掌握如何适当得使用线程,那么其几个状态必须要掌握的,这也是线程的生命周期。

如图所示:



线程定义的三种方式

继承Thread类

这种定义线程的方式是最简单的,但是一般不推荐。那这又是为什么呢?其实,这要看类与类之间的继承特点,我们应该都知道,类之间的继承属于单继承,而在以后的编码开发过程中,不能保证每一个类不能拥有父类,这样看来,如果再想使用继承Thread类的方式来定义线程,那么这样是行不通的。但是这种方式还是需要了解的,以下有个示例来让大家更好的理解。

/**
* 实现线程的方式一,继承Thread类
* Created by Cecilia on 2017/7/26.
*/
public class ThreadDemo extends Thread{

@Override
public  void run(){
for (int cnt=1;cnt<100;cnt++){
try {
System.out.println("线程1计数:"+cnt);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

public static void main(String[] args) {

//第一种定义线程的方式
ThreadDemo td = new ThreadDemo();
td.start();
}


实现Runnable接口

实现Runnable接口的方式虽然在开启线程的过程中代码比较复杂,但是这种方式一般对于没有返回值的线程而言是最好的选择。因为接口具有多继承的特点,凭借这优点,在程序员定义线程时会优先选择这种方式。同样的,提供一个例子,让其更好地去理解。

/**
* 实现线程的方式二,实现Runnable接口
* Created by Cecilia on 2017/7/26.
*/
public class RunnableDemo implements Runnable{

@Override
public  void run(){
for (int cnt=1;cnt<100;cnt++){
try {
System.out.println("线程2计数:"+cnt);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

public static void main(String[] args) {
//第二种定义线程的方式
RunnableDemo rd = new RunnableDemo();
Thread thread = new Thread(rd);
thread.start();
}


实现Callable接口(带有返回值的线程)

前面两种方式是最常见的,但是对于大数据开发者来说,有很多场景是需要带有返回值的多线程,比如爬虫,这些需要将数据存储在Mon共DB中,同时需要利用多线程来使其爬取效率比较高。当然,以一个例子来让其看下这种定义方式。在开启线程时,需要使用Future工具类来帮助开启。

/**
* 第三种定义线程方式:实现带有返回值的线程接口(JDK1.5以后)
* Created by Cecilia on 2017/7/26.
*/
public class CallableDemo implements Callable<String>{

@Override
public String call() throws Exception {

//Thread.sleep(1000);
//Sleep能不用就不用,可以使用TimeUnit
TimeUnit.MILLISECONDS.sleep(1000);
String message = "This is another message!";
return message;
}
}
public static void main(String[] args) {
//第三种定义线程方式
CallableDemo callableDemo = new CallableDemo();
FutureTask<String> futureTask = new FutureTask<>(callableDemo);
Thread thread1 = new Thread(futureTask);
thread1.start();
while(true){
if (futureTask.isDone()){                         //判断线程是否执行结束
try {
System.out.println(futureTask.get());     //获取返回值,线程阻塞
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}finally {
break;
}
}else{
try {
TimeUnit.MILLISECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  线程 多线程