文章目录
- 一、多线程
- 1、继承Thread类(方式一)
- 1)实现多线程
- 2)优缺点
- 2、实现Runnable接口(方式二)
- 1)实现多线程
- 2)实现多线程(匿名内部类方式)
- 3)优缺点
- 3、实现Callable、FutureTask接口(方式三)
- 1)实现多线程
- 2)优缺点
- 4、Thread线程
- 1)Thread的构造器
- 5、Thread的方法
- 1)Thread获取和设置线程名称
- 2)Thread类获得当前线程的对象
- 3)Thread类的线程休眠方法:
- 二、线程安全
- 三、线程同步
- 1、同步代码块
- 2、同步方法
- 3、Lock锁
一、多线程
1、继承Thread类(方式一)
1)实现多线程
继承Thread类
重写run()方法
创建线程对象
调用start()方法启动
调用run方法会当成普通方法执行,只有调用start方法才是启动一个新的线程执行
2)优缺点
- 优点
编码简单
- 缺点
是单继承,线程类继承Thread后,不能继承其他类,不便于扩展
2、实现Runnable接口(方式二)
1)实现多线程
定义一个线程任务类MyRunnable实现Runnable接口,重写run()方法
创建MyRunnable对象
把MyRunnable任务对象交给Thread线程对象处理
调用线程对象的start()方法启动线程
2)实现多线程(匿名内部类方式)
创建Runnable的匿名内部类对象
交给Thread处理
调用线程对象的start()启动线程
3)优缺点
- 优点
实现了Runnale接口,可以继续继承和实现
- 缺点
线程有执行结果是不能直接返回
3、实现Callable、FutureTask接口(方式三)
1)实现多线程
创建Callable接口实现类,重写call()方法,封装
用FutureTask把Callable对象封装成线程任务对象
线程任务对象交给Thread处理,调用start()方法启动线程,执行任务
执行完毕后,通过FutureTask的get方法去获取任务执行的结果
2)优缺点
- 优点
线程任务类只是实现接口,可以继续继承类和实现接口,扩展性强。
可以在线程执行完毕后去获取线程执行的结果。
- 缺点
编码复杂
方法名 | 解释 |
---|---|
public FutureTask(Callable call) | 把Callable对象封装成FutureTask对象 |
public V get() throws Exception | 获取线程执行call方法返回的结果 |
4、Thread线程
1)Thread的构造器
构造器 | 解释 |
---|---|
public Thread(String name) | 为当前线程指定名称 |
public Thread(Runnable target) | 封装Runnable对象成为线程对象 |
public Thread(Runnable target ,String name ) | 封装Runnable对象成为线程对象,并指定线程名称 |
public class MyRunnable implements Runnable{ @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println("Runnable "+Thread.currentThread().getName()+" ===>> "+i); } }}
public class ClassStructure { public static void main(String[] args){ MyRunnable myRunnable = new MyRunnable(); //分配一个带有指定目标新的线程对象 Thread thread = new Thread(myRunnable); //获取当前线程名称 String name = thread.getName(); System.out.println("当前名称-1:"+name); //设置新的名称 thread.setName("Thread-1-新"); String newName = thread.getName(); System.out.println("当前名称-1:"+ newName); //启动多线程 thread.start(); MyRunnable mr = new MyRunnable(); //分配一个带有指定目标新的线程对象并指定名称 Thread td = new Thread(mr,"指定名称:"); String strName = td.getName(); System.out.println("当前名称-2:"+ strName); td.start(); }}
5、Thread的方法
1)Thread获取和设置线程名称
方法名 | 解释 |
---|---|
String getName() | 获取当前线程的名称,默认线程名称是Thread-索引 |
void setName(String name) | 将此线程的名称更改为指定的名称,通过构造器也可以设置线程名称 |
public class ClassStructure { public static void main(String[] args){ Thread thread = new Thread(); String name = thread.getName(); System.out.println(name); thread.setName("线程1"); String nameNew = thread.getName(); System.out.println(nameNew); }}
2)Thread类获得当前线程的对象
方法名 | 解释 |
---|---|
public static Thread currentThread() | 返回对当前正在执行的线程对象的引用 |
注意:
1、此方法是Thread类的静态方法,可以直接使用Thread类调用。
2、这个方法是在哪个线程执行中调用的,就会得到哪个线程对象。
public class MyThread extends Thread { public MyThread(String name) { super(name); } @Override public void run() { super.run(); for (int i = 0; i < 10; i++) { //获得当前正在执行的线程对象 Thread td = Thread.currentThread(); //获取当前线程名称 System.out.println(td.getName() + i); } }}
3)Thread类的线程休眠方法:
方法名 | 解释 |
---|---|
public static void sleep(long time) | 让当前线程休眠指定的时间后再继续执行,单位为毫秒 |
public class MyThread extends Thread { public MyThread(String name) { super(name); } @Override public void run() { super.run(); for (int i = 0; i < 10; i++) { //获得当前正在执行的线程对象 Thread td = Thread.currentThread(); //获取当前线程名称 System.out.println(td.getName() + i); } }}
public class ClassStructure { public static void main(String[] args) throws InterruptedException { MyRunnable mr = new MyRunnable(); //分配一个带有指定目标新的线程对象并指定名称 Thread td = new Thread(mr,"指定名称:"); String strName = td.getName(); System.out.println("当前名称-2:"+ strName); System.out.println(System.currentTimeMillis()); //暂停3秒 Thread.sleep(3000); System.out.println(System.currentTimeMillis()); td.start(); }}
二、线程安全
多个线程同时访问同一个共享资源且存在修改该资源
三、线程同步
- 概念
解决线程安全问题
- 保证线程安全
多个线程实现先后依次访问共享资源,可以解决安全问题
- 思想
加锁:让多个线程实现先后依次访问共享资源,可以解决安全问题
1、同步代码块
- 原理
每次只能一个线程进入,执行完毕后自动解锁,其它线程才可以进来执行
- 作用
线程安全问题的核心代码给上锁
- 实现线程安全
对出现问题的核心代码是使用synchronized进行加锁
每次只能一个线程占锁进入执行
- 格式
synchronized(同步锁对象) {操作共享资源的代码(核心代码)}
- 同步锁对象要求
对于实例方法建议使用this作为锁对象
对于静态方法建议使用字节码(类名.class)对象作为锁对象
2、同步方法
- 原理
每次只能一个线程进入,执行完毕后自动解锁,其它线程才可以进来执行
- 作用
线程安全问题的核心代码给上锁
- 格式
- 实现线程安全
对出现问题的核心代码是使用synchronized进行加锁
每次只能一个线程占锁进入执行
修饰符 synchronized 返回值类型 方法名称(形参列表) {操作共享资源的代码}
- 同步锁对象要求
对于实例方法建议使用this作为锁对象
对于静态方法建议使用字节码(类名.class)对象作为锁对象
- 底层原理
如果方法是实例方法:同步方法默认用this作为的锁对象。但是代码要高度面向对象
如果方法是静态方法:同步方法默认用类名.class作为的锁对象
3、Lock锁
- 原理
锁对象Lock,使用更加灵活、方便
Lock实现提供比使用synchronized方法和语句可以获得更广泛的锁定操作
Lock是接口不能直接实例化,这里采用它的实现类ReentrantLock来构建Lock锁对象
方法名 | 解释 |
---|---|
public ReentrantLock() | 获得Lock锁的实现类对象 |
void lock() | 加锁 |
void unlock() | 解锁 |