引言
在现有的项目或者自己练手的项目中如果没有使用多线程这一技术,就表明这个项目不太全面可用度不高(本人认为)。因为高并发是目前趋势,尽管已当前现有的手段能够在一定程度上解决高并发问题,尽管出现了多线程、缓存、异步队列等手段,但是仍然不能够完全解决高并发问题。本篇文章将演示Java线程的创建方式以及其区别。
并发与并行
在多核CPU下
并发:是指同一时间应对多件事情的能力,多个线程轮流使用一个或者多个CPU。
并行:是指同一时间做多件事情的能力,多核CPU同时执行多个线程。
创建线程的方式
继承Thread类,子类重写run方法
测试
实现Runnable接口,重写run方法,作为参数传递给Thread
测试
实现Callable接口,设置泛型(对应方法返回值类型)
测试,抛出异常
线程池创建线程(下篇文章细讲线程池)
Runable与Callable的区别
- 注意观察两者的run方法返回值,Runnable中的run方法没有返回值,Callable中call方法返回值为指定的泛型类型。
- Callable可以配合使用Future、FutureTask用来获取异步执行的结果
Callable中的call方法允许抛出异常,Runnable中的run方法异常只能内部消化不能抛出
线程中start与run方法的区别
start():用来启动线程,通过线程调用run方法并且执行run方法中的代码,同时start方法只能调用一次。
run():封装了被执行的代码,可以多次调用。
多线程的使用(卖票案例)
多线程操作同一数据会引起数据脏读等问题,在这个案例中使用互斥锁ReentrantLock进行解决。最多只有一个线程可以修改票量stock。
线程类的编写
public class MyThread extends Thread {
//售卖的数量,同时为了多个线程同时访问使用static修饰
static int ticket=0;
//定义互斥锁
static Lock lock=new ReentrantLock();
@Override
public void run() {
//循环进入卖票
while (true)
{
//上锁
lock.lock();
try {
//卖票逻辑
if (ticket==100)
{
break;
}else {
Thread.sleep(1);
ticket++;
System.out.println(getName()+"---"+ticket);
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
//释放锁
lock.unlock();
try {
//防止一个线程一直拿到锁,休眠2秒
Thread.sleep(200);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
}
主类运行,构造三个线程
查看运行结果
总结
多线程是本人认为比较重要的一个基础点,日常的开发离不开而且面试也是经常出现的,希望同学们能够多学多练多思考!!