基本概念
程序是为了完成特定任务,用某种语言编写的一组指令的集合。即指一段静态的代码。
过程是程序的一次执行过程,或是正在运行的一个程序。是一个动态的过程:有他自身产生,存在和消亡的过程。进程作为资源分配的单位,系统在运行时会为每个进程分配不同的内存区域。
线程,进程的进一步的细化,是一个程序内部的执行路径。
多线程指一个进程在同一时间内并行执行多个线程。
线程作为调度和执行的单位,每个线程拥有独立的运行栈和程序计数器。容易带来安全隐患。
线程的创建和使用
创建方式一:继承于Thread类
1.创建一个继承于Thread类的子类
2.重写Thread类的run();重写的run方法中写的是此线程要执行的操作
3.创建Thread类的子类的对象
4.通过此对象调用start();
多线程创建方式二:通过继承Runnable接口创建多线程
1.创建一个实现了Runnable接口
2.实现类去实现Runnable中的抽象方法:run()
3.创建实现类的对象
4.将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
5.通过Thread类的对象调用start();
多线程创建方式三:通过Callable和Future创建线程:
实现步骤:①、创建Callable接口的实现类,并实现call()方法,改方法将作为线程执行体,且具有返回值。
②、创建Callable实现类的实例,使用FutrueTask类进行包装Callable对象,FutureTask对象封装了Callable对象的call()方法的返回值因为这个是泛型。如果需要改变,就需要在定义Future类时<需要返回的类>
③、使用FutureTask对象作为Thread对象启动新线程。
④、调用FutureTask对象的get()方法获取子线程执行结束后的返回值。
import java.util.concurrent.*;
class G implements Callable
{
@Override
public Object call() throws Exception {
System.out.println("123");
return null;
}
}
public class test {
public static void main(String[] ags){
FutureTask t=new FutureTask(new G());
new Thread(t).start();
}
}
继承Thread类和实现Runnable接口、实现Callable接口的区别。
继承Thread:线程代码存放在Thread子类run方法中。
优势:编写简单,可直接用this.getname()获取当前线程,不必使用Thread.currentThread()方法。
劣势:已经继承了Thread类,无法再继承其他类。
实现Runnable:线程代码存放在接口的子类的run方法中。
优势:避免了单继承的局限性、多个线程可以共享一个target对象,非常适合多线程处理同一份资源的情形。
劣势:比较复杂、访问线程必须使用Thread.currentThread()方法、无返回值。
实现Callable:
优势:有返回值、避免了单继承的局限性,可以返回异常、多个线程可以共享一个target对象,非常适合多线程处理同一份资源的情形。
劣势:比较复杂、访问线程必须使用Thread.currentThread()方法
建议使用实现接口的方式创建多线程。
Thread中的常用方法:
1.start():启动当前线程,调用当前线程的run()
2.run():通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中
3.currentThread():静态方法,返回当前代码的线程
4.getName():获得当前线程的名字
5.setName():设置当前线程的名字
6.yield():释放当前cpu的执行权
7.join():将当前线程挂起,直到join()方法加入的线程结束后再参加
8.stop():已过时,当执行此方法是,强制结束当前线程
9.sleep(long millitime):让当前线程“睡眠”指定的millitime毫秒。在指定的时间里当前线程堵塞/
10.isAlive():判断当前线程是否存活。
线程的调度
调度策略:
时间片:即CPU分配给各个程序的时间,每个线程被分配一个时间段,称作它的时间片,即该进程允许运行的时间,使各个程序从表面上看是同时进行的。
抢占式:高优先级的线程抢占CPU。
java的调度方法
同优先级线程组成的先进先出队列(先到先得服务),使用 时间片策略
对高优先级,使用优先调度的抢占式策略。
线程优先级
MAX_PRIORITY:10
MIN_PRIORITY:1
MORM_PRIORITY:5
获取当前线程的优先级:getPriority()
设置当前线程的优先级:setPriority(int p)
优先级大小是概率发生大小。
线程的生命周期
新建-当一个Thread类或其子类的对象被声明并创建时,新生的线程对象处于新建状态。
就绪-处于新建状态的线程被start()后,将进入线程队列等待Cpu时间片,此时它已经具备了运行的条件,只是没有分配到cpu资源。。
运行-当就绪的线程被调度并获得CPU资源时,便进入运行状态,run()方法定义了线程的操作和功能
阻塞-在某种特殊的情况下,被人为挂起或执行输入输出操作时,让出CPU并临时中止自己的执行,进入阻塞状态。
死亡-线程完成它的全部工作或线程被提前强制性地中止或出现异常导致结束。
线程的同步
当多线程切换速度太快,就容易发生一些错误,出现线程安全问题
问题出现的原因:当某个线程执行时,其他线程参加进来。
同步代码块可以解决:
synchronized(同步监视器){//需要被同步的代码,就是操作共享数据的代码}
同步监视器,俗称:锁。任何一个类的对象都可以充当锁。
这样这段代码就只能有一个线程执行,多个线程共用一个锁。解决了线程的安全问题
当定义为同步方法时,他的同步监视器是当前对象。
定义为静态同步方法时,他的监视器是当前类本身.
同步方法的总结:
1.动态的方法仍然涉及同步监视器,只是不需要我们显示的声明
2.非静态的同步监视器是:this
静态的同步方法·的同步监视器是当前类本身。
死锁
是因为在线程执行时,因为这段锁的代码中还有一把锁,而这把锁被另外一个线程使用,这个线程也在等他这把锁使用完成,双方都在等,程序不结束,形成了死锁。
LOCK锁
类ReentrantLock
类中的方法:lock()上锁
解锁:unlock()
线程的通信
涉及三个方法
wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器。
notify():一旦执行此方法,就会唤醒被wait的一个线程。如果有多个线程被wait(),就会唤醒优先级高的线程。
notifyAll():一旦执行此方法,就会唤醒所有被wait的线程。
线程池
背景:经常使用,使用量特别大的资源,比如在并发下对性能影响很大。
思路:提前创建好多个线程,放入线程池,使用时直接直接获得,放回池中。可以避免频繁创建销毁,类似生活中的交通工具。
好处:
- 提高响应速度(减少了创建新线程的时间)
- 降低资源消耗(重复利用线程池中线程,不需要每次都创建)
- 便于线程管理
- corePoolSize:核心池的大小
- maximumPoolSize:最大线程数
- keepAliveTime:线程没有任务时最多保持多长时间后会终结。
- 。。。
java-多线程
原文:https://www.cnblogs.com/gjdxjd/p/14386402.html