多线程
概念
线程
进程中负责程序执行的执行单元,一个进程至少有一一个线程。
多线程
解决多任务同时执行的需求 ,合理使用CPU资源。多线程的运行时根据CPU切换完成,如何切换由CPU决定,因此多线程运行具有不确定性
创建线程
继承Thread类,扩展线程
1 2 3 4 5 6 7 8 9 |
class DemoThread extends Thread { @Override public void run() { super.run(); // Perform time-consuming operation... } } DemoThread t = new DemoThread(); t.start(); |
- 继承Thread类,扩展线程
- 创建线程对象,用start()方法启动线程。
实现Runnable接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
public class Test2 { public static void main(String[] args) { //创建对象 MyRunnable mr = new MyRunnable(); Thread t = new Thread(mr); //启动 t.start(); try{ for(int i = 0;i < 10;i++){ Thread.sleep(1000); System.out.println("main:" + i); } }catch(Exception e){} } } /** * 使用实现Runnable接口的方式实现多线程 */ public class MyRunnable implements Runnable { public void run() { try{ for(int i = 0;i < 10;i++){ Thread.sleep(1000); System.out.println("run:" + i); } }catch(Exception e){} } } |
- 实现Runnable接口
- 使用new Thread(Runnable实现对象),创建线程
问题
线程和进程之间的区别
一个进程时一个独立的运行环境,它可以被看作一个程序或者一个应用。线程是在进程中执行的一个任务。线程是进程的子集,一个进程可以有很多线程,每条线程并行执行不同的任务。不同的进程使用不同的内存空间,而所有的线程共享一片相同的内存空间,每个线程都拥有的栈内存来存储本地数据。
如何在Java中实现线程
1、继承Thread类,重写方法。
2、实现Runnable接口。
start()方法与Run()方法的区别
调用start()方法是启动新线程,线程之间没有确定执行顺序,而是CPU决定的;如果直接调用run方法,则是像普通方法一样顺序执行。
多线程优缺点
优点
- 适当提高程序的执行效率(多个线程并行)
- 适当提高资源利用率
缺点
- 占用一定的内存空间
- 线程越多CPU调度开销越大
- 程序复杂度上升
线程状态转换
图
状态
1、新生状态
2、就绪状态
3、运行状态
4、阻塞状态
阻塞状态是由于正在运行的线程未结束,暂时让出了CPU
5、死亡状态
1、 run方法正常退出而自然死亡,
2、 一个未捕获的异常终止了run方法而使线程猝死。
方法
wait(),notify(),notifyAll()
wait():
导致线程进入等待状态,直到它被其他线程通过notify()或者notifyAll()唤醒,该方法只能在同步方法中调用。
notify():
随机选择一个在该对象上调用wait()方法的线程,解除其阻塞状态,该方法只能在同步方法或者同步块内部调用。
notifyAll():
解除所有那些在该对象上调用wait方法的线程的阻塞状态,同样方法只能在同步方法或者同步块内部调用。
wait()与sleep(long time)的区别
sleep():在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),该线程不丢失任何监视器的所属权,sleep() 是 Thread 类专属的静态方法,针对一个特定的线程。
wait() 方法使实体所处线程暂停执行,从而使对象进入等待状态,直到被 notify() 方法通知或者 wait() 的等待的时间到。sleep() 方法使持有的线程暂停运行,从而使线程进入休眠状态,直到用 interrupt 方法来打断他的休眠或者 sleep 的休眠的时间到。
wait() 方法进入等待状态时会释放同步锁,而 sleep() 方法不会释放同步锁。所以,当一个线程无限 sleep 时又没有任何人去 interrupt 它的时候,程序就产生大麻烦了,notify() 是用来通知线程,但在 notify() 之前线程是需要获得 lock 的。另个意思就是必须写在 synchronized(lockobj) {…} 之中。wait() 也是这个样子,一个线程需要释放某个 lock,也是在其获得 lock 情况下才能够释放,所以 wait() 也需要放在 synchronized(lockobj) {…} 之中。
volatile关键字
volatile是一个特殊的修饰符,只有成员变量才能使用,使变为可见,保证下一个读取操作会在前一个写操作后发生。
join()
将一个线程插入到另一个线程中执行。
Thread.yield()
线程放弃运行,将CPU控制权让出。
yield() 方法让出控制权后,还有可能马上被系统的调度机制选中来运行