一、什么是进程、线程以及两者的关系
-
进程 (Process): 是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。(引用自百度百科)
进程的概念主要有两点:
第一,进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)、数据区域(data region)和堆栈(stack region)。文本区域存储处理器执行的代码;数据区域存储变量和进程执行期间使用的动态分配的内存;堆栈区域存储着活动过程调用的指令和本地变量。
第二,进程是一个“执行中的程序”。程序是一个没有生命的实体,只有处理器赋予程序生命时(操作系统执行之),它才能成为一个活动的实体,我们称其为进程。
在我们的电脑任务管理器中可以看到如下图所示的就是进程:
-
线程(Thread):是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。线程共享进程资源。
二、线程的创建方式
1. 继承(extends)
继承Thread并重写run()方法,如下代码所示:
/**
* <p>Title:MyThread</p>
* <p>Description:创建线程之继承</p>
* @author XuelinR
* @date 2019年5月30日
*
*/
class MyThread extends Thread {
/* (non-Javadoc)
* <p>Title:run</p>
* <p>Description:线程体中写要实现的业务逻辑</p>
* @see java.lang.Thread#run()
*/
@Override
public void run() {
System.out.println("我是线程体。");
}
}
2. 实现(implements)
这种方式是实现创建线程的接口,有两种方式:
a.实现Runnable接口
/**
* <p>Title:TestThread</p>
* <p>Description:实现接口Runnable</p>
* @author XuelinR
* @date 2019年5月30日
*
*/
class MyThread implements Runnable {
/* (non-Javadoc)
* <p>Title:run</p>
* <p>Description:</p>
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
System.out.println("我是线程体。");
}
}
b.实现Callable接口,此方式创建线程会有返回值
/**
* <p>Title:MyThread</p>
* <p>Description:实现Callable接口,有返回值</p>
* @author XuelinR
* @date 2019年5月30日
*
*/
class MyThread implements Callable<String>{
/* (non-Javadoc)
* <p>Title:call</p>
* <p>Description:</p>
* @see java.util.concurrent.Callable#call()
*/
@Override
public String call() throws Exception {
System.out.println("我是线程体。");
return null;
}
}
三、线程的状态
- 线程从创建到结束的生命周期中包含了以下状态:
- 下图包含了创建、就绪、阻塞、运行等各阶段的运行方式
四、线程的应用
1、线程的启动(静态代理)
- 继承Thread时线程启动:
MyThread mt = new MyThread();
mt.start();
- 实现Runnable时线程启动:
//实际类
TestThread tt = new TestThread();
//代理类,利用了代理类中的start方法
Thread proxy = new Thread(tt);
proxy.start();
2、线程池管理多线程
- 一个有意思的故事:模拟龟兔赛跑
/**
* <p>Title:Race</p>
* <p>Description:比赛类</p>
* @author XuelinR
* @date 2019年5月30日
*
*/
class Race implements Callable<Integer>{
private String name;//名称
private long time;//用时
private Boolean flag = true;//控制循环
private int step = 0;//步数
public Race() {
}
/**
* @param name
*/
public Race(String name) {
super();
this.name = name;
}
/**
* @param name
* @param time
*/
public Race(String name, long time) {
super();
this.name = name;
this.time = time;
}
/* (non-Javadoc)
* <p>Title:call</p>
* <p>Description:线程体,步数递增</p>
* @see java.util.concurrent.Callable#call()
*/
@Override
public Integer call() throws Exception {
while (flag) {
Thread.sleep(time);
step++;
}
return step;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the time
*/
public long getTime() {
return time;
}
/**
* @param time the time to set
*/
public void setTime(long time) {
this.time = time;
}
/**
* @return the flag
*/
public Boolean getFlag() {
return flag;
}
/**
* @param flag the flag to set
*/
public void setFlag(Boolean flag) {
this.flag = flag;
}
/**
* @return the step
*/
public int getStep() {
return step;
}
/**
* @param step the step to set
*/
public void setStep(int step) {
this.step = step;
}
}
main方法中测试
public static void main(String[] args)
throws InterruptedException, ExecutionException {
//调用线程池创建两个线程
ExecutorService executor = Executors.newFixedThreadPool(2);
Race tortoise = new Race("千年乌龟",1000);
Race rabbit = new Race("小兔子",500);
//获取值
Future<Integer> r1 = executor.submit(tortoise);
Future<Integer> r2 = executor.submit(rabbit);
Thread.sleep(2000);
//停止循环
tortoise.setFlag(false);
rabbit.setFlag(false);
//获取返回步数
int num1 = r1.get();
int num2 = r2.get();
System.out.println("千年乌龟跑了<"+num1+">步");
System.out.println("小兔子跑了<"+num2+">步");
//关闭线程池
executor.shutdown();
}
3、线程安全
- 并发:多个线程访问同一份资源
- 同步(synchronized):保证资源具有原子性
注:过多的同步会造成线程死锁 - 单例模式之同步:
package designpattern.singleton;
/**
* @author XuelinR
* 单例模式
* 创建步骤:a、私有的静态属性;b、构造器私有化;c、对外提供公共的静态的访问方法。
* 1、懒汉式
*/
public class Singleton {
//私有的静态属性
private static Singleton singleton = null;
//构造器私有化
private Singleton() {
}
//提供对外的公共访问方法,这里要确保在多线程访问时的安全性
//double check
public static Singleton getInstence() {
if(null == singleton) {
synchronized(Singleton.class){
if(null == singleton) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
/**
*
* <p>Title:Singleton2</p>
* <p>Description:单例模式之饿汉式</p>
* @author XuelinR
* @date 2019年5月30日
* 2、饿汉式
*/
class Singleton2 {
//私有的静态属性,这里一开始就创建对象
private static Singleton2 singleton = new Singleton2();
//构造器私有化
private Singleton2() {}
//对外提供公共的访问方法
public static Singleton2 getInstence() {
return singleton;
}
}
/**
* <p>Title:Singleton3</p>
* <p>Description:单例模式之饿汉式内部类</p>
* @author XuelinR
* @date 2019年5月30日
*
*/
class Singleton3 {
//创建私有的静态的内部类,延迟加载,确保在使用对象时加载,提高性能
private static class SingletonHoder{
private static Singleton3 singleton = new Singleton3();
}
//构造器私有化
private Singleton3() {}
//对外提供公共的静态的访问方法
public static Singleton3 getInstence() {
return SingletonHoder.singleton;
}
}
- 生产者消费者模式,解决多线程访问死锁的问题
/**
* <p>Title:Movie.java</p>
* <p>Description:</p>
* @author XuelinR
* @date 2019年5月30日
* @version
*/
package threads;
/**
* <p>Title:Movie</p>
* <p>Description:生产者、消费者</p>
* @author XuelinR
* @date 2019年5月30日
*
*/
public class Product {
private String pic;
//
private boolean flag = true;
/**
* <p>Title:produce</p>
* <p>Description:生产</p>
* @param pic
*/
public synchronized void produce(String pic){
//Producer
if (!flag) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//begin product
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.pic = pic;
System.out.println("produce:"+pic);
//over produce
this.notify();
//stop produce
this.flag = false;
}
/**
* <p>Title:consume</p>
* <p>Description:消费</p>
*/
public synchronized void consume() {
//Consumer
if (flag) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("consume:"+pic);
//over consume
this.notify();
//stop consume
this.flag = true;
}
//测试生产者消费者
public static void main(String[] args) {
Product pt = new Product();
Producer pd = new Producer(pt);
Consumer cs = new Consumer(pt);
new Thread(pd).start();
new Thread(cs).start();
}
}
生产者:
/**
* <p>Title:Producer.java</p>
* <p>Description:</p>
* @author XuelinR
* @date 2019年5月30日
* @version
*/
package threads;
/**
* <p>Title:Producer</p>
* <p>Description:</p>
* @author XuelinR
* @date 2019年5月30日
*
*/
public class Producer implements Runnable {
private Product pt;
/**
* @param m
*/
public Producer(Product pt) {
super();
this.pt = pt;
}
/* (non-Javadoc)
* <p>Title:run</p>
* <p>Description:</p>
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
for (int i = 0; i < 50; i++) {
if (i%2==0) {
pt.produce("三国演义");
} else {
pt.produce("西游记");
}
}
}
}
消费者:
/**
* <p>Title:player.java</p>
* <p>Description:</p>
* @author XuelinR
* @date 2019年5月30日
* @version
*/
package threads;
/**
* <p>Title:player</p>
* <p>Description:生产者</p>
* @author XuelinR
* @date 2019年5月30日
*
*/
public class Consumer implements Runnable {
private Product pt;
/**
* @param m
*/
public Consumer(Product pt) {
super();
this.pt = pt;
}
/* (non-Javadoc)
* <p>Title:run</p>
* <p>Description:</p>
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
for (int i = 0; i < 50; i++) {
pt.consume();
}
}
}