线程简介
程序,程序是指令和数据的有序集合,静态的概念。
进程则是齿形程序的一次执行过程,是个动态概念,是系统资源分配的单位。
一个进程可以包含若干个线程,线程是CPU调度和执行的单位。
很多多线程是模拟出来的,因为切换很快,所以有同时执行的错觉。
真正的多线程,是多个cpu。
注意:
main()称之为主线程,为系统的入口,用于执行整个程序。
不能认为干预多个线程的先后顺序。
对同一份资源操作,会存在资源抢夺的问题,需要加入并发控制。
线程会带来额外的开销。
线程实现(重点)
1.线程创建(三种创建方式)
Thread class,继承Thread类(重点)
Runnable接口,实现Runnable接口(重点)
Callable class,实现Callable接口
2.Thread类
使用
自定义线程类继承Thread类
重写run()方法
创建一个线程对象,调用start方法开启线程
如下所写;
public class Application extends Thread{
@Override
public void run(){
for (int i = 0; i < 2000; i++) {
System.out.println("AAA");
}
}
public static void main(String[] args) {
Application one = new Application();
one.start();
for (int i = 0; i < 2000; i++) {
System.out.println("BBB");
}
}
}
3.Runnable接口(可以多继承)
实现runnable接口,
重写run方法,
执行线程丢入runnable接口实现类,调用start方法。
public class Application implements Runnable{
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("看代码呢");
}
}
public static void main(String[] args) {
Application application = new Application();
new Thread(application).start();
for (int i = 0; i < 20; i++) {
System.out.println("玩呢");
}
}
}
注意:new Thread(对象,线程名称)建立一个线程对象
4.Callable接口(了解)
5.Thread类方法
Thread.sleep()延迟
Thread.currentThread().getName()得到名称
6.Lamda表达式
前提知识:匿名内部类
Ilove ilove = new Ilove(){
public void love(){};
}
Ilove为接口
优势:可以让你的代码看起来很简洁
去掉一堆没有意义的代码,只留下核心的逻辑
任何接口,如果只有一个抽象方法,就是函数式接口,
可以用lamada表达式创建该接口的对象。
用法:接口 名称 = () -> {};
翻译:简化了一次性使用的匿名内部类,由于接口只提供一个方法,直接()->{ } 可以书写该对象继承接口的方法
曲线救国级理解:定义了一个匿名类,并定义了接口的方法
7.静态代理模式
真实对象和代理对象要实现统一接口。
代理对象用target表示真实对象。
好处:
代理对象可以做很多真实对象做不了的事情
真实对象专注做自己的事情
public class TestLamda2{
public static void main(String[] args) {
new WeddingPlanner(() -> System.out.println("hi")).HappyMarry();
}
}
interface Marry{
void HappyMarry();
}
class WeddingPlanner implements Marry{
private Marry target;
public WeddingPlanner(Marry target){
this.target = target;
}
public void HappyMarry() {
this.target.HappyMarry();
}
}
暂时理解:传参相当于Marry target = ()->sout("hi")
与线程的联系:Thread设个Runnable的接口,(不用lamda表达)Runnable A = B,
(用lamda表达)Runnable A = ()->{ }
线程状态
1.停止线程(外置判断暂停)
推荐线程自己停止下来
public class TestLamda2{
private static boolean flag = true;
public static void main(String[] args) {
Runnable runnable = ()->{
int i = 0;
while(flag){
if(i==1000)flag=false;
System.out.println("小线程"+i++);
}
};
new Thread(runnable).start();
for (int i = 0; i < 1000; i++) {
System.out.println("主线程"+i);
if(i==900){
stop();
System.out.println("线程停止了");
break;
}
}
}
static void stop(){
flag = false;
}
}
2.线程休眠(Thread.sleep)
模拟延迟Thread.sleep(毫秒数)
sleep存在异常InterruptedException
sleep时间达到后线程进入就绪状态
sleep可以模拟网络延时,倒计时
每个对象都有一个锁,sleep不会释放锁
3.线程礼让(Thread.yield)
礼让线程,让当前正在执行的线程暂停,但不阻塞
讲线程从运行状态转化就绪状态
让cpu重新调度,礼让不一定成功
4.插队线程(Thread.join)
5.线程状态
类名Thread.State = XX.getState();
新生NEW,运行Runnable,延迟TIMED——WAIIING,结束TERMINATED
6.线程优先级
优先级数 1~10
线程对象.setPriority(级数)
7.守护(daemon)线程
线程分为用户线程和守护线程(伴随虚拟机的开始和结束)
虚拟机必须确保用户线程执行完毕
虚拟机不用等待守护线程执行完毕(后台记录操作日志,监控内存)
线程同步(重点)
多个线程操作同一个资源
队列:线程同步其实就是一种等待机制,多个需要同时访问此对象的线程进入这个对象的等待池形成队列,等待前面线程使用完毕,下一个线程再使用。
锁:为了保证数据在方法中被访问是的正确性,在访问时加入锁机制,当一个线程获得对象的排它锁,独占资源,其他线程必须等待,使用后释放锁即可。
1.同步方法
public synchronized void methode(int args){ }
加上synchronized关键字,就能锁住该方法
默认锁的是本身.
2.同步块
synchronizded (Obj){ }
Obj表示被锁的对象(是变化的量)
3.JUC里的安全类型集合
CopyONWriteArrayList
4.死锁
解决方式,用完锁就赶紧放
5.Lock
实现类Reentranlock
使用:定义lock锁,然后推荐try{XX.lock()锁住}finally{lock,unlock解锁}
线程协作(用Obj自带的方法)
1.管程法
建立一个数组,添加生产的产品,然后消费产品,如果为NULL,就会等待
2.信号灯法
建立一个boolea,判断是否继续该线程,要不要等待
使用线程池
ExecutorService:真正的线程池接口(实现类ThreadPoolExecutor)
Executor:工具类
使用
ExecutorService service = Executors.newFixedThreadPool(大小)//创建服务,创建线程池
service.execute(线程对象)//执行
service.shutdown()//关闭连接