程序、进程、线程
程序:(Program)
程序是计算机为了完成某种功能而使用计算机语言编写的指令集。是一段静态的代码或静态的对象。程序不能单独直接执行,必须放在内存中等待操作系统为其分配资源后才能执行。
进程:(Process)
进程即正在进行(执行)的程序,进程是操作系统进行资源分配的最小单位。
线程(Thread)
线程是进程中的最小执行单元,是CPU调度和分派的最小基本单位。线程没有自己的操作系统资源,而是与同属进程的其他线程共享该进程所拥有的全部资源。
进程和线程的关系
1.一个进程中可以包含多个线程(一个QQ可以有多个聊天窗口)
2.一个线程只能隶属于一个进程(QQ聊天窗口只能属于QQ进程)
3.一个进程中至少包含一个线程(主线程 java中的main方法就是用来启动主线程的)
4.在主线程中可以创建并启动其他线程
5. 一个进程的线程共享该进程的内存资源
创建线程
方法一
继承Thread类的方式
1.创建一个类,继承Thread并重写父类的run方法,
run方法中是用来编写线程中要执行的内容,或者在run方法中调用其他的方法。
2.然后在main函数中调用start方法即可。
方法二
实现Runnable接口的方式
1.先创建一个类,实现Runnable接口,并重写run方法,在run方法中写下要执行的线程任务。
2.在main方法中创建刚刚的任务对象,并创建Thread对象,将任务对象作为参数传入。
3.启动start方法
【实现Runnable的好处】
1)避免了单继承的局限性
2)多个线程可以共享同一个接口实现类的对象,非常适合多个相同线程来处 理同一份资源
方法三
实现Callable泛型接口
相比run方法,call方法有以下优点:
1.可以有返回值 方法可以抛出异常
2.支持泛型的返回值
3.需要借助FutureTask类,获取返回结果
线程中基本的方法
控制线程状态的方法
1.sleep()
该方法可以让线程停止指定时间后再执行
2.join()
该方法可以让程序在执行完threadtest01线程后再执行其他线程
3.yield()
该方法可以使正在执行的线程退回队列中重新排队。
购票系统案例
用synchronized锁来控制只允许一个线程进入购票。
创建两个线程来同时购票
锁
synchronized同步锁关键字
同步锁对象
修饰非方法时:
作用:记录有没有线程进入同步代码块
要求:多个线程对应同一个同步锁对象
修饰方法时:
非静态方法,则同步锁对象为this对象
静态方法,同步锁对象为当前类的对象
Reentrantlock类
reentrantlock类在使用的使用,只能修饰代码块,不能修饰方法。
该类需要手动加锁,手动释放(因此释放锁一般放在finally中)
synchronized和Reentantlock的区别
1.synchronized是关键字,控制依靠底层编译后的指令去实现。Reentantlock是一个类,依靠java代码区控制(底层有个同步队列)
2.synchronized可以修饰方法和代码块,Reentantlock只能修饰代码块
3.synchronized是隐式的加锁和释放锁,一旦方法或代码块中运行结束或出现异常,就会自动释放。Reentantlock需要手动加锁,手动释放
线程通信
wait()
非静态方法,可以使当前线程进入堵塞状态,并且自动释放锁对象
notify()
非静态方法,可以唤醒一个wait状态的线程,如果有多个线程在wait状态,则按照其优先级进行排序唤醒。
notifyAll()
非静态方法,可以唤醒所有wait状态的线程。
wait(),notify(),notifyAll()三个方法必须使用在同步代码块或同步方法中
sleep和wait方法的区别
1.sleep方法是Thread类中的静态方法,wait是Object类中的非静态方法。
2.sleep必须让线程休眠指定时间后才能被自动唤醒,wait可以被notify和notifyAll唤醒。
3.sleep只是让线程休眠,但不会释放锁,其他线程仍然不能进来。wait让当前线程休眠后,会释放锁,其他线程可趁机进来。
消费者和生产者案例
柜台类:
消费者类:
测试类: