一个进程可以包含一个以上的多个线程
程序运行时,后台会自动创造线程,例如main(), gc
main()称为主线程,用于执行整个程序
线程的运行由调度器调度,先后顺序不能人为干预
对同一份资源操作时会存在资源抢夺问题,需要加入并发控制
线程会带来额外开销,如cpu调度时间,并发控制开销
每个线程在自己的工作内存交互,内存控制不当会造成数据不一致
继承Thread类
实现Runnable接口
实现runnable接口
重写run方法
丢入runnable接口实现类
或者 new Thread(testThread3).start();
注:推荐使用方法2,避免单继承局限性一个thread对象可以开启多个线程
调用start()执行
实现Callable接口
代理对象和被代理对象(真实对象)实现同种接口,通过用代理对象来实现被代理(真实)对象的功能,例如将真实对象传递给代理对象来调用其功能。
好处时代理对象可以做很多真实对象做不了的事情,真实对象可以只专注做自己的事情
避免匿名内部类定义过多
让代码更简洁
实质上属于函数式编程的概念:
任何只包含一个抽象方法的接口就是一个函数式接口。
我们通过lambda表达式创建对象必须是对于函数式接口。
因为接口只有一个方法,所以只用写实现其核心的代码实现就可以调用这个方法(类,接口,方法的名字都不用写了),是对匿名内部类的进一步简化:(抽象方法和类名都是love)
注:多行代码就不能去掉{},多个参数就不能去掉(),要去掉参数类型就要所有参数类型一起去掉
而runnable就是一个函数式接口,故可以用到lambda表达式
创建状态,就绪状态,阻塞状态,运行状态:死亡状态
注:线程优先值高意味着有更大可能性被执行,并不一定就先执行,优先级的设定建议在start()调度前
线程分为用户线程和守护线程
虚拟机必须确保用户线程执行完毕(例如main线程)
虚拟机不用等待守护线程执行完毕(例如记录操作日志,垃圾回收,监控内存)
thread.setDaemon(true):默认false表示用户线程,正常的线程都是用户线程,true设置为守护线程
并发:同一个对象被多个线程操作。
线程同步其实就是一种等待机制,多个需要访问同一个对象的线程进入这个对象的等待池形成队列,等待前面使用完毕下一个线程再使用。
线程同步安全形成条件:队列+锁。一个线程获得对象的锁, 独占资源,其他需要此锁的线程必须等待。多线程竞争下,加锁释放锁会导致性能下降,如果一个优先级高的线程等待一个优先级低的线程释放锁,会导致优先级倒置,引起性能问题。
线程安全和线程不安全的集合:
Vector、HashTable、Properties是线程安全的; ArrayList、LinkedList、HashSet、TreeSet、HashMap、TreeMap等都是线程不安全的。 值得注意的是:为了保证集合是线程安全的,相应的效率也比较低;线程不安全的集合效率相对会高一些。
多个线程各自占有一些共享资源,并且互相等待其他线程占有的资源才能运行,导致两个或者多个线程等待对方释放资源,都停止执行。某一个同步块同时拥有两个以上对象的锁时,就可能会发生死锁问题。