-
并发:指两个或多个事件在同一个时间段内发生 交替执行
-
并行:指两个或多个事件在同一时刻发生(同时发生) 同时执行
-
进程:一个内存中运行的应用程序
-
线程:是进程的一个执行单元,负责程序的执行 效率高,多个线程之间互不影响
线程
创建线程2中方法
一、 将类声明为Thread类的子类,该子类重写Thread类的run方法。
实现步骤:
- 创建Thread类的子类
- 在Thread类的子类中重写Thread类中的run方法。设置线程任务(开启线程要做什么)
- 创建Thread类的子类对象
- 调用Thread类中的方法 start,开启新的线程,执行run方法
public class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("run" + "--->" + i);
}
}
}
public class Demo01Thread {
public static void main(String[] args) {
MyThread mt = new MyThread();
mt.start();
for (int i = 0; i < 20; i++) {
System.out.println("main" + "--->" + i);
}
}
}
- Thread类中的方法
- getName() 返回该线程的名称
- currentThread() 获取到当前正在执行的线程
- SetName(String name) 设置线程的名称 或者在Thread类中蛇者带参数的构造方法, super(name)
- sleep() 使当前正在执行的线程以指定的毫秒数暂停
二、 第二种方法:声明实现Runable接口的类。实现run方法
实现步骤
- 创建一个Runnable接口的实现类
- 在实现类中重写 Runnable接口的run方法,设置线程任务
- 创建一个Runnable接口的实现类对象
- 创建Thread类对象,构造方法中传递Runnable接口的实现类对象
- 调用Thread类中的start方法,开启新的线程执行run方法
实现Runnable接口创建多线程程序的好处:
- 避免了单继承的局限性
- 一个类只能继承一个类,类继承了Thread类就不能继承其他的类
- 实现Runnable接口还可以继承其他的类,实现其他的接口
- 增强了程序的扩展性,降低了程序的耦合性
- 实现Runnable接口的方法,把设置线程任务和开启新线程进行了分离(解耦)
- 实现类中,重写了run方法,用来设置线程任务
- 创建Thread类对象,调用start方法,用来开启新的线程
匿名内部类的方式实现线程的创建
- 简化代码:
- 把子类继承父类,重写父类的方法,创建子类对象合成一步完成
- 把实现类实现类接口,重写接口的方法,创建实现类对象合成一步完成
线程安全问题
多线程访问共享数据,会产生线程安全问题
想吃安全问题是不能产生的,我们可以让一个线程在访问共享数据的时候,无论是否失去了cpu的执行权,让其他的线程只能等待
保证:只有一个线程在执行
- 解决线程安全问题:三种方法
- 同步代码块
- 同步方法
- Lock锁机制
1、解决线程安全问题 ----同步代码块
解决线程安全问题的一种方案:使用同步代码块
synchronized(锁对象){}
注意:
1. 通过代码块中的锁对象,可以使用任意的对象
2. 但是必须保证多个线程使用的锁对象是一个
3. 锁对象的作用:把同步代码锁住,只让一个线程在同步代码块中执行
同步技术的原理:
- 使用了一个锁对象,这个锁对象叫做同步锁,也叫异步锁,也叫作对象监视器
- 同步中的线程,没有执行完毕不会释放锁。同步外的线程没有锁进不去同步
2、解决线程安全问题 ----同步方法
使用步骤:
1. 把访问了共享数据的代码抽取出来,放到一个方法中
2. 在方法上添加synchronized 修饰符
格式:
修饰符 synchronized 返回值类型 方法名(参数列表){}
原理:
同步方法也会把方法内部的代码锁住
只让一个线程执行
同步方法的对象就是是实现类对象 new RunnableImpl()
也就是this
静态方法的锁对象是本类的class属性 --> class 文件对象(反射)
2、解决线程安全问题 ----使用Lock锁
Lock接口中的方法
- lock()
- unlock()
实现步骤:
1. 在成员位置创建一个Reentrantlock对象
2. 在可能会出现安全问题的代码前调用Lock接口中的方法lock 获取锁
3. 在可能会出现安全问题的代码前调用Lock接口中的方法unlock释放锁
线程的状态
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mixNa07z-1570465532094)(en-resource://database/7492:1)]
新建(NEW)、运行(RUNNABLE)、阻塞(BLOCK)、死亡、睡眠、无限等待(WAITING)
-
wait
-
sleep
-
notify
1、线程间通信
多个线程在处理同一个资源,但处理的动作(线程的任务)不同
2、生产者消费者问题
线程池
线程池:容器 --> 集合(ArrayList, HashSet, LinkedList, HashMap)
LinkedList
当程序第一次执行的时候,创建多个线程,保存在一个集合中,当我们想要使用线程的时候,就可以从集合中取出来线程使用。
在JDK1.5之后,JDK内置了线程池,我们可以直接使用。
java.util.concurrent.Executor线程池的工厂类,用来生成线程池
Executors类中的静态方法:
static ExecutorService newFixedThreadPool(int nThreads) 创建一个可重用的固定线程数的线程池
-
ExecutorService 线程池接口
- 用来从线程池中获取线程,调用start方法,执行线程任务
- submit(Runnable task)提交一个 Runnable 任务用于执行
- 关闭/销毁线程池的方法
- void shutdown()
线程池的使用步骤
- 使用线程池的工厂类 Executor 里面提供的荆条方法 newFixedThreadPool 生成一个指定线程数量的线程池
- 创建一个类,实现Runnable接口,重写run方法,设置线程任务
- 调用ExecutorService中的方法 submit ,传递线程任务(实现类)。开启线程,执行run方法
- 调用ExecutorService中的方法 shutdown,销毁线程池
- 用来从线程池中获取线程,调用start方法,执行线程任务
package ybs.paulson.ThreadPool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/*
- 使用线程池的工厂类 Executor 里面提供的荆条方法 newFixedThreadPool 生成一个指定线程数量的线程池
- 创建一个类,实现Runnable接口,重写run方法,设置线程任务
- 调用ExecutorService中的方法 submit ,传递线程任务(实现类)。开启线程,执行run方法
- 调用ExecutorService中的方法 shutdown,销毁线程池
*/
public class Demo01ThreadPool {
public static void main(String[] args) {
// 1、使用线程池的工厂类 Executor 里面提供的荆条方法 newFixedThreadPool 生成一个指定线程数量的线程池
ExecutorService es = Executors.newFixedThreadPool(2);
// 3、 调用ExecutorService中的方法 submit ,传递线程任务(实现类)。开启线程,执行run方法
// 线程池会一直开启,使用完了线程,会自动的把线程还给线程池,线程可以继续使用
es.submit(new RunnableImpl()); // 创建新的线程
es.submit(new RunnableImpl());
es.submit(new RunnableImpl());
es.submit(new RunnableImpl());
es.submit(new RunnableImpl());
es.shutdown();
// es.submit(new RunnableImpl()); // 抛出异常,线程池没有了,不能获取线程
}
}
package ybs.paulson.ThreadPool;
public class RunnableImpl implements Runnable {
@Override
public void run() {
// 1、创建一个类,实现Runnable接口,重写run方法,设置线程任务
System.out.println(Thread.currentThread().getName() + "创建了一个新的线程");
}
}