1、基本概念
1、程序
是完成特点的任务,用用某种语言编写的一组指令的集合,指一段静态代码,静态对象。
2、进程
是程序的一次执行过程。
3、线程
什么时候需要多线程:
(1)、程序需要通知执行两个或多个任务。
(2)、程序需要实现一些需要等待的任务时,如用户输入、文件读写操作、网络操作、搜索。
(3)、需要一些后台运行的程序时。
多线程的优点:
(1)、提高应用程序的响应。对图形化界面根由意义,可增强用户体验
(2)、提高计算机系统的cpu的利用率
(3)、改善程序结构,将即长有复杂的进程分为多个线程,独立运行,利于理解和修改。
2、线程的创建和使用
多线程创建:
方式一:(通过继承Thread类实现)
1、通过创建继承Thread类的子类,重写run()方法(如果需要多个线程,就创建几个子类(可以创建匿名子类))
2、在run()方法中写出需要同时进行的代码
3、在主线程中创建子类对象
4、调用子类对象继承的Thread类的start()方法执行
方式二:(通过Runnable接口实现)
1、通过创建引用接口的实现类,重写run()方法。
2、在run方法中写出同时进行的代码
3、在主线程中创建实现类
4、再将实现类作为Thread的构造参数传递。
5、在调用Thread类的start()方法执行
方式一与方式二对比:
优先选择方式二。。。
原因:
1、方式一通过继承实现多线程,继承中只能单一继承,而接口可以实现多个,造成功能短缺。
2、实现的方式更适合来处理多个线程所有共享数据的情况
相同点:
方式一和方式二都是通过实现Runnable接口实现的
匿名类的创建:
多线程的使用:
常用方法:
(1)、currentThread()方法,表示执行的线程
(2)、getName()方法,返回当前线程的名称,反之设置
(3)、yield()方法,释放当前线程的cpu执行权
(4)、join()方法,将当前线程执行完成,再返回执行权给优先级更高的线程
(5)、sleep(long millis)方法,是该线程休眠多少毫秒
(6)、setPriority(int newPriority)方法,设置当前线程的优先级
实例:
继承Thread方法实现:
升级为Runnable接口实现多线程:
3、线程的生命周期
新建、就绪、运行、阻塞、死亡;
4、线程的同步
解决问题:可以解决相关的重复或者超过范围的数据,解决线程安全问题; 方式一:使用同步代码块,实现Runnable接口的线程安全 1、首先要实现多线程, 2、在找出同步(共享)的数据 3、使用synchronized(同步监视器){ 共享的数据变化的(代码块) },进行线程同步(数据共享一致) 同步监视器:俗称:(锁),可以是任意对象,但必须是可以通过唯一的锁,可以创建Object对象来造锁,但考虑执行效率,可以调用this(继承的Thread的多 线程,不行)。 实例: | |||
解决线程安全的方式三: Lock(锁): 通过创建Reentrantlock类实现了Lock; ReentrantLock reentrantLock = new ReentrantLock(); //调用重入锁对象中的方法,返回一个condition(条件)对象 Condition condition = reentrantLock.newCondition(); lock()方法,上锁 condition.await()方法,将该线程放在等待集中 condition.signalAll()方法,解除该条件等待中所有线程的阻塞状态 condition.sinal()方法,从该条件的等待集中随机选择一个线程,解除其自身阻塞状态 unlock() 方法,解锁; 示例: | |||
方式二:使用同步方法解决,实现Runnable接口的线程安全
总结:
1、同步方法仍然涉及到同步监视器,只是不要我们显示声明。
2、非静态的同步方法,同步监视器是:this。
静态的同步方法,同步监视器是:当前类的本身。
示例:
5、线程的通信
使用前提:wait,notify,notifyAll,三个方法必须使用在同步代码块或同步方法中的同步监视器必须相同。
涉及的方法:
wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器;
notify():一旦执行此方法,就会唤醒被wait的一个线程,如果有多个线程被
就唤醒优先级高的线程
notifyAll():一旦执行此方法,就会唤醒所有被wait的线程
注意:三个方法都是定义在java.lang.Object类中。
面试题:sleep()和wait()的异同?
1、相同点,都可以使得当前的线程进入阻塞状态。
2、不同点:
(2)、两个方法声明位置不同,Thread类中声明sleep(),Object类中声明wait()
(3)、调用的要求不同,sleep()可以在任何场景下调用,wait()必须在同步代码块或者同步方法中使用
(4)关于是否释放同步监视器:如果两个方法都使用同步代码块或同步方法中,sleep()方法不会是释放同步监视器,wait()方法会释放同步监视器
6、JDK5/0新增线程创建方式
新增方式一:实现Callable接口
与使用Runnable相比,Callable功能更强大些
1、相比run()方法,call()方法,拥有返回值;
2、在call()方法中可以抛出异常,外面可以捕获。
3、支持泛型。
实现方式:
1、定义一个类引用Callable接口,重写call()方法;
2、在主线程中创建实体类,
3、将实体类作为参数,传递给FutureTask构造方法;(通过futureTask类可以调用Call()方法返回值)
4、再将FutureTask实体类作为参数,传递给Thread构造方法;
5、在调用Thread的start()方法启动线程;
示例:
方式二:使用线程池:
1、使用Executors执行器的静态构造方法,造线程池
2、如果需要配置线程池信息,就要进行强转至具体实现类中(ThreadPoolExecutor类)中调用方法
3、再将需要多线程处理的对象作为参数传入execute()方法中
4、最后在关闭线程池,使用shutdown()方法。
示例:
以上是个人学习的过程,有不正确的地方,请大家指正!