多线程
1.什么是进程
2.什么是线程
3.进程和线程的区别
- 1.进程是操作系统资源分配的基本单位,而线程是cpu的基本调度单位
- 2.一个程序运行后至少有一个进程
- 3.一个进程可以包含多个线程,但是至少需要一个线程,否则这个进程是没有意义的。
- 4.进程间不能共享数据段地址,但同进程的线程之间可以。
4.线程的组成
- 任何一个线程都具有基本的组成部分:
- CPU时间片:操作系统(os)会为每个线程分配执行时间。
- 运行数据
- 堆空间:存储线程需使用的对象,多个线程可以共享堆中的对象。
- 栈空间:存储线程需使用的局部变量,每个线程都拥有独立的栈。
- 线程的逻辑代码
5.线程的特点
- 1.线程抢占式执行
- 效率高
- 可防止单一线程长时间独占cpu
- 2.在单核cpu中,宏观上同时执行,微观上顺序执行。
6.创建线程
- 创建线程的三种方式
- 1.【继承Thread类,重写run方法】
- 2.【实现Runnable接口】
- 3.实现Callable接口
注意:启动线程,不能调用run方法,不然就是一个普通方法的调用,而不是启动线程。
7.获取和修改线程名称
- 获取线程ID和线程名称
- 1.在Thread的子类中调用this.getId()或this.getName();
- 2.使用Thread.currentThread().getId()和Thread.currentThread().getName();
- 修改线程名称
- 1.调用线程对象的setName()方法
- 2.使用线程子类的构造方法赋值。
注意:创建MyRunnable对象,表示线程要执行的功能。而是一个线程。
8.线程的状态(基本)
9.常见方法
- 休眠
- public static void sleep(long millis)
- 当前线程主动休眠mollis毫秒。
- 放弃
- public static void yield()
- 当前线程主动放弃时间片,回到就绪状态,竞争下一次时间片。
- 加入:
- public final void join()
- 允许其他线程加入到当前线程中。
注意:加入当前线程(main),并堵塞当前线程,直到加入线程执行完毕
- 优先级
- 线程对象.setPriority()
- 线程优先级为1-10,默认为5,优先级越高,表示获取cpu机会越多。
- 守护线程
-线程对象.setDaemon(true);设置为守护线程- 线程有两类:用户线程(前台线程),守护线程(后台线程)
- 如果程序中所有前台线程都执行完毕了,后台线程会自动结束。
- 垃圾回收器线程属于守护线程。
10.线程的状态(等待)
11.线程的安全问题
- 多线程安全问题
- 当多线程并发访问临界资源时,如果破坏原子操作,可能会造成数据不一致。
- 临界资源:共享资源(同一对象),一次仅允许一个线程使用,才可保证其正确性。
- 原子操作:不可分割的多步操作,被视作一个整体,其顺序和步骤不可打乱或缺省。
12.同步方式(1)
- 同步代码块:
synchronized(临界资源对象){//对临界资源对象加锁
//代码(原子操作)
}
注:每个对象都有一个互斥锁标记,用来分配给线程的。
只有拥有对象互斥锁标记的线程,才能进入对该对象加锁的同步代码块
线程退出同步代码块时,会释放相应的互斥锁标记。
13.线程的状态(阻塞)
14.同步方式(2)
- 同步方法:
synchronized 返回值类型 方法名称(形参列表0){//对当前对象(this) 加锁
//代码(原子操作)
}
注意:如果是普通方法,锁是当前对象,如果是静态方法,锁是当前类。
注:只有拥有对象互斥锁标记的线程,才能进入对该对象加锁的同步代码块
线程退出同步代码块时,会释放相应的互斥锁标记。
15.同步规则
- 注意:
- 只有在调用包含同步代码块的方法,或者同步方法时,才需要对象的锁标记。
- 如果用不包括同步代码块的方法,或普通方法时,则不需要锁标记,可直接调用。
- 已知JDK中线程安全的类:
- StringBuffer
- Vector
- Hashtable
- 以上类中的公开方法,均为synchonized修饰的同步方法。
16.经典问题
- 死锁
- 当第一个线程拥有A对象锁标记,并等待B对象锁标记,同时第二个线程拥有B对象锁标记,并等待A对象锁标记时,产生死锁。
- 一个线程可以同时拥有多个对象的锁标记,当线程阻塞时,不会释放已经拥有的锁标记,由此可能造成死锁。
17. 线程通信
- 等待:
- public final void wait()
- public final void wait(long timeout)
- 必须在对obj加锁的同步代码块中,在一个线程中,调用obj.wait()时,此线程会释放其拥有的所有锁标记。同时此线程阻塞在o的等待队列中。释放锁,进入等待队列。
- 通知:
- public fianl void notify()
- public final void notifyAll()
可能存在的问题如下: