程序:
进程:运行中的程序(被加载到内存中),是操作系统中分配的最小单位;
线程:进程可以进一步细化为线程,是进程内一个最小执行单元,是CPU进行任务调度的最小单位。
进程与线程的关系:
一个进程可以包含多个线程
一个线程只能隶属于一个进程,线程也不能脱离进程存在
一个进程中至少有一个线程(即主线程),main方法就是用来启动主线程
在主线程中可以创建并启动其他线程
所有线程共享同一进程内存资源。
早期没有线程,早期CPU执行的时候,是以进程为单位执行,进程单位较大,当一个进程运行时,其他进行就不能运行,所以后来,将进程中的多个任务,细化为线程,CPU执行单位,也从进程转为更小的单位。
需求:想在java程序中有几件不相关的事情同时有机会执行。
可以在java中创建线程,把一些要执行的任务放在线程中执行。
java中创建线程的方式:
继承Thread(线程)类,重写Thread类中的run()方法,在run()中来编写我们需要执行的任务代码。
public class javaThread extends Thread{
@Override
public void run(){
for (int i=0;i<2000000000;i++){
System.out.println("Thread:"+i);
}
}//线程执行任务的方法
public static void main(String[] args) {
for (int i=0;i<1000000000;i++){
System.out.println("main:"+i);
}
javaThread javathread=new javaThread();
javathread.start();//启动线程,并不会是立即执行,需要操作系统的调度。切记不能直接调用run()方法,因为run()方法只是一个普通方法调用,并不是启动线程。
}
}
实现Runnable接口(这个类不能称为线程,是一个任务类)并重写Runnable中的run()方法
public class TaskDemo implements Runnable{
@Override
public void run(){
for (int i=0;i<1000;i++){
System.out.println("task:"+i);
}
}
public static void main(String[] args) {
TaskDemo taskDemo=new TaskDemo();
Thread thread=new Thread(taskDemo);
Thread thread1=new Thread(taskDemo);
thread.start();
thread1.start();
for (int i=0;i<1000;i++){
System.out.println("main:"+i);
}
}
}
注:
一般第二种用的更多一点,因为可以一次性实现多个接口;
更适合多线程共享同一份资源的场景。
构造方法
new Thread(Runnable runnable);//接收一个任务对象
new Thread(Runnable runnable,String)//接收一个任务对象,并为线程设置名字
setName("name");//为我的线程设置名字
getName("name");//获取线程名字
getPriority();//获取线程优先级
setPriority();//设置线程优先级,默认为5,高优先级的线程优先被处理
/*
操作系统任务调度算法:
先来先服务(FCFS)调度算法;
短作业优先(SJF)调度算法;
优先级调度算法;
时间片轮转调度算法;
高响应比优先调度算法;
多级反馈队列调度算法;
*/
sleeep(long m);//让线程休息指定毫秒
join();//让其他线程等待当前线程结束后再执行
线程生命周期,线程从创建到销毁经历:
new Thread(); 处于新建状态,此时还不能被执行
start();启动线程,让线程进入到就绪状态
获得CPU执行权后,线程进入到CPU执行
运行中的线程可以被切换,回到就绪状态,也可能因为休眠等原因进入到阻塞状态
线程休眠时间到了,回到就绪状态
当线程中所有任务执行完了,线程也自动销毁
守护线程也是线程中的一种,区别在于它的结束
如果一个线程是守护线程,那么它会等java中其他的线程任务结束后,自动终止。
守护线程是为其他线程提供服务的,例如jvm中的垃圾回收线程。
在一个应用程序中,存在多个线程,不同的线程可以并行的执行任务
提高程序的处理能力,杀毒软件,垃圾清理,病毒查杀
线程越多,占用的内存和CPU越多;
多个线程对同一个共享的资源进行访问,会出现线程安全问题。
如何解决多个线程访问同一个共享资源时不出问题?
同步=排队+锁(synchronized)
锁的使用规范:
//买票系统
public class Ticket extends Thread{
static int t=1000;//剩余的票
static Object object=new Object();
@Override
public void run() {
/*
synchronized修饰代码块
同步对象:对多个线程对应的对象必须是同一个
用来记录有没有线程进入到同步代码块中的
同步对象可以是java中任何类的对象
创建了两个卖票的对象,锁有两把
synchronized(同步对象){
同步代码块
}
*/
synchronized(object){
while (true){
try {
if(t>0){
System.out.println(Thread.currentThread().getName()+"买到了"+t);
t--;
}else{
break;
}
Thread.sleep(100);
}catch (Exception e){
e.printStackTrace();
}
}
}
}
}
public class test extends Thread{
public static void main(String[] args) {
Ticket ticket=new Ticket();
ticket.setName("窗口1");
Ticket ticket1=new Ticket();
ticket1.setName("窗口2");
ticket1.start();
ticket.start();
}
}
synchronized修饰方法,同步对象会有默认的
修饰的是非静态方法那么同步对象是this
修饰的是静态方法那么同步对象是当前类的Class对象
当前类的Class对象:一个类加载到内存后会为这个类创建一个唯一的Class类的对象。
ReentrantLock reentrantlock=new ReentrantLock();//提供一个实现加锁的对象
reentrantLock.lock();//加锁
reentrantLock.unlock();//释放锁
相同点:都实现了加锁的功能;
不同点:
一旦执行此方法,当前的线程就会进入阻塞状态,并释放同步锁对象
让线程等待,自动释放锁,必须等待至其他线程唤醒
一旦执行此方法,就会唤醒被wait()的一个线程。如果有多个线程被wait,就唤醒优先级高的那个
一旦执行此方法,就会唤醒所有被wait的线程