多线程概述
多线程的创建方式
1、继承Thread类:
步骤:①、定义类继承Thread;
②、复写Thread类中的run方法;
目的:将自定义代码存储在run方法,让线程运行
③、调用线程的start方法:
· 该方法有两步:启动线程,调用run方法。
2、实现Runnable接口: 接口应该由那些打算通过某一线程执行其实例的类来实现。类必须定义一个称为run 的无参方法。
实现步骤: ①、定义类实现Runnable接口
②、覆盖Runnable接口中的run方法
将线程要运行的代码放在该run方法中。
③、通过Thread类建立线程对象。
④、将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。
自定义的run方法所属的对象是Runnable接口的子类对象。所以要让线程执行指定对象的run方法就要先明确run方法所属对象
⑤、调用Thread类的start方法开启线程并调用Runnable接口子类的run方法。
3、通过Callable和Future创建线程:
实现步骤:①、创建Callable接口的实现类,并实现call()方法,改方法将作为线程执行体,且具有返回值。
②、创建Callable实现类的实例,使用FutrueTask类进行包装Callable对象,FutureTask对象封装了Callable对象的call()方法的返回值
③、使用FutureTask对象作为Thread对象启动新线程。
④、调用FutureTask对象的get()方法获取子线程执行结束后的返回值。
通常,线程池都是通过线程池工厂创建,再调用线程池中的方法获取线程,再通过线程去执行任务方法。
同步的前提:
同步代码块中的锁对象可以是任意的对象;但多个线程时,要使用同一个锁对象才能够保证线程安全。
同步方法中的锁对象是 this
静态同步方法中的锁对象是 类名.class
1、必须要有两个或者两个以上的线程。
2、必须是多个线程使用同一个锁。
3、必须保证同步中只能有一个线程在运行。
4、只能同步方法,不能同步变量和类。
5、不必同步类中所有方法,类可以拥有同步和非同步的方法。
6、如果一个线程在对象上获得一个锁,就没有任何其他线程可以进入(该对象的)类中的任何一个同步方法。
7、线程睡眠时,它所持的任何锁都不会释放。
好处:解决了多线程的安全问题。
弊端:多个线程需要判断,消耗资源,降低效率。
注意:还可以通过Lock接口 new 实现类对象(Reentrantlock)创建锁
等待唤醒机制
线程之间的通信:多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同。通过一定的手段使各个线程能有效的利用资源。而这种手段即—— 等待唤醒机制。
wait() :等待,将正在执行的线程释放其执行资格 和 执行权,并存储到线程池中。
notify():唤醒,唤醒线程池中被wait()的线程,一次唤醒一个,而且是任意的。
notifyAll(): 唤醒全部:可以将线程池中的所有wait() 线程都唤醒。
唤醒的意思就是让 线程池中的线程具备执行资格
代码示例
public class Mytest {
public static void main(String[] args) {
/* 创建两个线程:一个线程打印 100个A,一个线程打印 100 个 B
输出效果:ABABAB.....交替打印 */
Print print = new Print();
PrintA printA = new PrintA(print);
PrintB printB = new PrintB(print);
Thread thread1 = new Thread(printA);
Thread thread2 = new Thread(printB);
thread1.start();
thread2.start();
}
}
public class Print {
boolean flag;
}
public class PrintA extends Thread{
private Print object;
public PrintA(Print object){
this.object = object;
}
@Override
public void run() {
synchronized (object) {
for (int i = 1; i <= 100; i++) {
if (object.flag!=false){
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.print('A');
object.flag = true;
object.notify();
}
}
}
}
public class PrintB extends Thread{
private Print object;
public PrintB(Print object){
this.object = object;
}
@Override
public void run() {
synchronized (object) {
for (int i = 1; i <= 100; i++) {
if (object.flag!=true) {
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.print('B');
object.flag = false;
object.notify();
}
}
}
}