多进程和多线程的概念
进程是程序在计算机上的一次执行活动。当你运行一个程序,你就启动了一个进程。凡是用于完成操作系统的各种功能的进程就是系统进程,而所有由你启动的进程都是用户进程。
多进程
进程是程序在计算机上的一次执行活动。当你运行一个程序,你就启动了一个进程。凡是用于完成操作系统的各种功能的进程就是系统进程,而所有由你启动的进程都是用户进程。
如图所示每一个正在运行的 .exe 程序都是一个进程。
多线程
进程就是有一个或多个线程构成的。而线程是进程中的实际运行单位,是独立运行于进程之中的子任务。是操作系统进行运算调度的最小单位。可理解为线程是进程中的一个最小运行单元。
进程和线程之间的关系
一个进程下包含 N 个线程。
举例说明:玩英雄联盟的时候,打开客户端便启动了许多个线程:排队队列线程、好友聊天线程、正在支付线程。在英雄联盟这一个进程之下便启动了 N 个线程。
我们初学 java 边写代码的时候,通常使用 main 方法进行运行,此时 main 方法执行的便是一个主线程,而所谓的多线程,即是在主线程执行的过程中,同时执行其他的线程。
但是同时执行多个线程容易出现报错现象,例如同时同分同秒,两个线程同时修改一个 txt、数据库表文件,或第一个线程没有修改完 txt、数据库表文件,第二个线程同时也去修改。这便是线程之间的混乱、资源竞争、脏读,便是程序员需要去解决的疑难杂症。
创建多线程——继承 Thread
java 世界中有两种方式创建多线程
java 世界中有两种方式创建多线程,分别是继承 Thread 类,实现 Runnable 接口。
继承 Thread 类方式创建多线程
第一步:在 webide 上右键单击菜单,选择 New File 创建新文件。
第二步:创建文件 test0.java。
第三步:编写 test0.java 中继承 Thread 类方式创建多线程的代码如下所示:
public class test0 { public static void main(String[] args) { Thread MyThread = new MyThread(); MyThread.start(); } } class MyThread extends Thread { @Override public void run() { System.out.println(“hello myThread” + Thread.currentThread().getName()); } }
第四步:编译 test0.java 代码:
javac test0.java
编译之后,会产生我们所编写的 test0 类与 MyThread 类
第五步:运行 test 代码:
java test0
创建多线程——实现 Runnable
只需要把《创建多线程——继承 Thread》中代码修改成如下所示即可,其它操作不变:
public class test0 {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start();
}
}
class MyRunnable implements Runnable{
@Override
public void run(){
System.out.println("hello myRunnable" + Thread.currentThread().getName());
}
}
public class test0 { public static void main(String[] args) { MyRunnable myRunnable = new MyRunnable(); Thread thread = new Thread(myRunnable); thread.start(); } } class MyRunnable implements Runnable{ @Override public void run(){ System.out.println(“hello myRunnable” + Thread.currentThread().getName()); } }
执行结果如下所示:
通常情况下,如果创建的线程类已经含有父类时候,此时由于 Java 语法结构不支持多继承的原因,不能够再次继承 Thread 类,此时则需要使用实现 Runnable 接口的方式来应对如此场景。
另外值得说明的是,Thread 类也实现了 Runnable 接口。
实现多线程传参——有参构造
由于多线程是由继承 Thread 或实现 Runnable 并重写 run() 方法,通过 thread.start() 进行运行的,而本身重写的 run() 方法是不具备传参能力的,那我新建的线程就接受不到我所想传入的参数了么?
创建 study1.java 文件
class ThreadA extends Thread{
private String age;
public ThreadA(String age){
this.age = age;
}
@Override
public void run() {
System.out.println("age=" + age);
}
}
public class study1 {
public static void main(String[] args) {
String age = new String("12");
ThreadA a = new ThreadA(age);
a.start();
}
}
class ThreadA extends Thread{ private String age; public ThreadA(String age){ this.age = age; } @Override public void run() { System.out.println(“age=” + age); } } public class study1 { public static void main(String[] args) { String age = new String(“12”); ThreadA a = new ThreadA(age); a.start(); } }
无论 extends Thread 还是 implements Runnable ,传参都需要使用线程初始化的有参构造形式,达到多线程传参的目的。也可以做到重载有参构造,传入各式对象。
study1 运行结果
实现多线程返回值——实现 Callable
通常意义上理解确实 Java 实现多线程的方式有继承 Thread 和实现 Runnable,但是如果想实现多线程并且具有返回值的情况下,需要实现 Callable
创建 study2.java
创建 study2.java 文件,利用实现 Callable
import java.util.concurrent.Callable;
public class study2 {
public static void main(String[] args) {
MyCallable MyCallable = new MyCallable("张方兴");
String call = null;
try {
call = MyCallable.call();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(call);
}
}
class MyCallable implements Callable<String>{
private String name;
public MyCallable(String name) {
this.name = name;
}
@Override
public String call() throws Exception {
return "call:" + name;
}
}
import java.util.concurrent.Callable; public class study2 { public static void main(String[] args) { MyCallable MyCallable = new MyCallable(“张方兴”); String call = null; try { call = MyCallable.call(); } catch (Exception e) { e.printStackTrace(); } System.out.println(call); } } class MyCallable implements Callable
study2 运行结果
Callable 接口详解
一般继承 Thread 的类,含有 .start() 函数,所以直接可以使用 .start() 函数进行启动。
实现 Runnable 的类,需要通过 new Thread(myRunnable).start(); 的方式进行启动,即实现 Runnable 的类只是做好了一段多线程所需执行的内容,自身并没有执行的能力,需要通过 Thread 类的 .start() 函数进行启动。
实现 Callable
@FunctionalInterface
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
@FunctionalInterface public interface Callable
Callable
另外注意,函数接口的实例可以使用 lambda 表达式、方法引用或构造函数引用创建。
- Callable
在需要使用返回值的情况下,程序是同步运行的 - Callable
其它情况下,程序是异步运行的
在阅读 Callable