一、什么是进程?什么是线程?

操作系统可以同时支持多个程序的运行,而一个程序可以狭义的认为就是一个进程。在一个进程的内部,可能包含多个顺序执行流,而每个执行流就对应一个线程。

1.1、进程

进程:是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位。当程序进入内存运行时,即为开启了一个进程。

进程的特点:

  • 独立性:进程是系统中独立的实体,可以拥有独立的资源
  • 动态性:进程是动态的,它有自己的生命周期
  • 并发性:多个进程可以并发运行,互不影响

并发性和并行性是不同的概念:并行是指同一时刻,多个命令在多个处理器上同时执行;并发是指在同一时刻,只有一条命令是在处理器上执行的,但多个进程命令被快速轮换执行,使得在宏观上具有多个进程同时执行的效果。

1.2、线程

线程:是程序内部的顺序执行流。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。线程并不拥有自己的系统资源,它与其他线程一起分享进程的系统资源。

【举例】

public class Test {

    public static void main(String[] args) {
Thread th = Thread.currentThread();
System.out.println("Tread name:" + th.getName());
method();
} public static void method() {
Thread th = Thread.currentThread();
System.out.println("Tread name:" + th.getName());
}
}

执行结果:(当java程序启动的时候,会启动一个由主方法(public static void main(String[] args))所开启的主线程main)

Tread name:main
Tread name:main

执行过程如下:

程序的执行过程:首先把程序的代码放到内存的代码区里面,代码放到代码区后并没有马上开始执行,但这时候说明了一个进程准备开始,进程已经产生了,但还没有开始执行,平常所说的进程的执行指的是进程里面主线程开始执行了,也就是main()方法开始执行了,在我们机器里面实际上运行的都是线程。

线程状态:

线程总共有5大状态

  • 新建状态:新建线程对象,并没有调用start()方法之前
  • 就绪状态:调用start()方法之后线程就进入就绪状态,在变为当前线程之前都是为就绪状态。值得一提的是,线程从阻塞状态中恢复的时候也会进入就绪状态
  • 运行状态:线程被设置为当前线程,开始执行run()方法。就是线程进入运行状态
  • 阻塞状态:线程被暂停,比如说调用sleep()方法后线程就进入阻塞状态
  • 死亡状态:线程执行结束

二、如何创建多个线程?

2.1、继承Thread类

【举例】

public class MyThread extends Thread {

    private String params;

    public MyThread(String params) {
this.params = params;
} @Override
public void run() {
Thread thread = Thread.currentThread();
System.out.println(this.params + ":" + thread.getName());
}
}
public class Test {

    public static void main(String[] args) {
Thread th = Thread.currentThread();
System.out.println("main():" + th.getName());
threadTest1();
threadTest2();
method();
} public static void threadTest1() {
MyThread myThread = new MyThread("threadTest1");
myThread.start();
} public static void threadTest2() {
MyThread myThread = new MyThread("threadTest2");
myThread.run();
} public static void method() {
Thread th = Thread.currentThread();
System.out.println("method():" + th.getName());
}
}

执行结果:

main():main
threadTest2:main
method():main
threadTest1:Thread-0

调用myThread.start()方法,会开启一个新的线程Thread-0。而调用run()方法时,不会开启一个新的线程,仍然是单线程模式。

2.2、实现Runnable接口

【举例】

public class MyThread implements Runnable {

    private String params;

    public MyThread(String params) {
this.params = params;
} @Override
public void run() {
Thread thread = Thread.currentThread();
System.out.println(this.params + ":" + thread.getName());
}
}
public class Test {

    public static void main(String[] args) {
Thread th = Thread.currentThread();
System.out.println("main():" + th.getName());
threadTest1();
threadTest2();
method();
} public static void threadTest1() {
MyThread myThread = new MyThread("threadTest1()");//这种线程创建方式有很多弊端,使用Executors提供的线程池更好
myThread.run();
} public static void threadTest2() {
MyThread myThread = new MyThread("threadTest2()");
Thread thread = new Thread(myThread);
thread.start();
} public static void method() {
Thread th = Thread.currentThread();
System.out.println("method():" + th.getName());
}
}

执行结果:

main():main
threadTest1():main
method():main
threadTest2():Thread-0

实现Runnable接口和继承Thread类这两种开辟新线程的方法,应该优先选择实现Runnable接口。因为接口可以实现多个,而类只能是单继承。

2.3、实现Callable接口

实现Callable接口的好处在于可以获取到线程的返回值,关于Callable和Future,我们会在后面再详细的介绍。

【举例】

public class CallThread implements Callable<Integer> {

    @Override
public Integer call() {
int i = 0;
for (; i < 100; i++) {
Thread thread = Thread.currentThread();
System.out.println(i + "\t" + thread.getName());
}
return i;
}
}
public class Test {

    public static void main(String[] args) throws ExecutionException, InterruptedException {

        CallThread callThread = new CallThread();
FutureTask<Integer> ft = new FutureTask<>(callThread);
Thread thread = new Thread(ft);//这种线程创建方式有很多弊端,使用Executors提供的线程池更好
thread.start();
System.out.println("返回值:" + ft.get());
System.out.println("===============");
Thread thread1 = Thread.currentThread();
System.out.println("线程:" + thread1.getName());
}
}

执行结果:

0    Thread-0
1 Thread-0
2 Thread-0
3 Thread-0
4 Thread-0
5 Thread-0
6 Thread-0
7 Thread-0
8 Thread-0
9 Thread-0
返回值:10
===============
线程:main

虽然程序中打开了两个线程,但是由于需要获取到Thread-0线程的返回值(ft.get()),所以Thread-0线程和main线程并不能并发执行,只有当Thread-0线程执行结束,才可以继续执行main线程。

【修改】

public class Test {

    public static void main(String[] args) throws ExecutionException, InterruptedException {

        //CallThread callThread = new CallThread();
//修改为lambda表达式
FutureTask<Integer> ft = new FutureTask<>(()->{
int i = 0;
for (; i < 10; i++) {
Thread thread = Thread.currentThread();
System.out.println(i + "\t" + thread.getName());
}
return i;
});
Thread thread = new Thread(ft);
thread.start();
//System.out.println("返回值:" + ft.get());
System.out.println("===============");
Thread thread1 = Thread.currentThread();
System.out.println("线程:" + thread1.getName());
}
}

执行结果:

===============
0 Thread-0
1 Thread-0
2 Thread-0
3 Thread-0
4 Thread-0
5 Thread-0
6 Thread-0
7 Thread-0
线程:main
8 Thread-0
9 Thread-0

当把“System.out.println("返回值:" + ft.get());”注释掉以后,两个线程就可以并发执行了。

2.4、Future设置超时时间

        String result;
ExecutorService executor = Executors.newSingleThreadExecutor();
FutureTask<String> future =
new FutureTask<>(new Callable<String>() {
public String call() throws InterruptedException {
TimeUnit.SECONDS.sleep(4);
return "ok";
}
});
executor.execute(future);
//在这里可以做别的任何事情
try {
result = future.get(5000, TimeUnit.MILLISECONDS); //取得结果,同时设置超时执行时间为5秒。同样可以用future.get(),不设置执行超时时间取得结果。
System.out.println(result);
} catch (InterruptedException e) {
future.cancel(true);
} catch (ExecutionException e) {
future.cancel(true);
} catch (TimeoutException e) {
future.cancel(true);
} finally {
executor.shutdown();
}

设置超时时间,如果超过5秒还没有返回值,则抛出超时异常

JAVA基础知识|进程与线程的更多相关文章

  1. JAVA基础知识之多线程——线程池

    线程池概念 操作系统或者JVM创建一个线程以及销毁一个线程都需要消耗CPU资源,如果创建或者销毁线程的消耗源远远小于执行一个线程的消耗,则可以忽略不计,但是基本相等或者大于执行线程的消耗,而且需要创建 ...

  2. JAVA基础知识之多线程——线程组和未处理异常

    线程组 Java中的ThreadGroup类表示线程组,在创建新线程时,可以通过构造函数Thread(group...)来指定线程组. 线程组具有以下特征 如果没有显式指定线程组,则新线程属于默认线程 ...

  3. JAVA基础知识之多线程——线程通信

    传统的线程通信 Object提供了三个方法wait(), notify(), notifyAll()在线程之间进行通信,以此来解决线程间执行顺序等问题. wait():释放当前线程的同步监视控制器,并 ...

  4. JAVA基础知识之多线程——线程同步

    线程安全问题 多个线程同时访问同一资源的时候有可能会出现信息不一致的情况,这是线程安全问题,下面是一个例子, Account.class , 定义一个Account模型 package threads ...

  5. JAVA基础知识之多线程——线程的生命周期(状态)

    线程有五个状态,分别是新建(New).就绪(Runnable).运行(Running).阻塞(Blocked)和死亡(Dead). 新建和就绪 程序使用new会新建一个线程,new出的对象跟普通对象一 ...

  6. JAVA基础知识之网络编程——-网络基础(Java的http get和post请求,多线程下载)

    本文主要介绍java.net下为网络编程提供的一些基础包,InetAddress代表一个IP协议对象,可以用来获取IP地址,Host name之类的信息.URL和URLConnect可以用来访问web ...

  7. Java多线程基础:进程和线程之由来

    转载: Java多线程基础:进程和线程之由来 在前面,已经介绍了Java的基础知识,现在我们来讨论一点稍微难一点的问题:Java并发编程.当然,Java并发编程涉及到很多方面的内容,不是一朝一夕就能够 ...

  8. 1、Java多线程基础:进程和线程之由来

    Java多线程基础:进程和线程之由来 在前面,已经介绍了Java的基础知识,现在我们来讨论一点稍微难一点的问题:Java并发编程.当然,Java并发编程涉及到很多方面的内容,不是一朝一夕就能够融会贯通 ...

  9. java基础知识小总结【转】

    java基础知识小总结 在一个独立的原始程序里,只能有一个 public 类,却可以有许多 non-public 类.此外,若是在一个 Java 程序中没有一个类是 public,那么该 Java 程 ...

随机推荐

  1. 【原创】大叔经验分享(84)spark sql中设置hive.exec.max.dynamic.partitions无效

    spark 2.4 spark sql中执行 set hive.exec.max.dynamic.partitions=10000; 后再执行sql依然会报错: org.apache.hadoop.h ...

  2. 【转】[STL]vector和deque的内存释放(clear)

    vector的clear成员函数可以清除vector中的元素,使其大小减至0.但它却不能减小vector占用的内存. [cpp] view plain copy int main() { vector ...

  3. 如何让某些用户对Marketing Cloud的contact数据只能实施只读操作

    打开maintain business role这个应用: 创建一个新的business role,然后添加下列这几个catalogs: SAP_CEC_BC_MKT_ADM_PC Marketing ...

  4. maven项目下pom.xml依赖报错

    百度了好几次,说是在本地仓库下少plugin,但是找了之后,发现并没有少呀

  5. iframe中的target属性

    在使用iframe的时候,我们有时候会遇到,外面的链接,去操作iframe中的页面 <!DOCTYPE html> <html> <head> <meta c ...

  6. php首页定向到内页代码

    php首页定向到内页代码,index.php头部加上以下代码, /afish-c-1/换成内页链接即可. if($_SERVER["REQUEST_URI"]=='/' || $_ ...

  7. 关于MVC设计模式下的Model

    内容1: 1.大多数情况下,会有两个关于Model的文件. 一个称他为Entity Model,他里面的字段一般是与数据库直接交互的,也就是说,Entity里面每一个字段赋予的属性都是对应着数据库来的 ...

  8. 大数据之路week04--day05(java 正则表达式)

    1.1 正则表达式 1.2 简介 Regular Expression  正则表达式   常简称为: regex.正则 正则表达式是一整套约束字符串的语法规则,独立于任何编程语言 正则表达式 方便.灵 ...

  9. Lua 学习之基础篇十<Lua 常见的语法规则>

    下面讲一些lua 常见的用法和规则,可以为学习理解lua带来帮助,最后附上的部分是lua的基本操作,基本包含所有常用语法语句. 1. if判断 lua把 nil 和false 视为"假&qu ...

  10. pip报错:解决pkg_resources.DistributionNotFound: The 'pip==7.1.0' distribution was not found and is required by the application

    如果pip安装后提示依然没有pip命令,需在在添加环境变量 # vim /etc/profile 在文档最后,添加: export PATH="/usr/local/python2.7/bi ...