线程基础(上)

线程

1.程序、线程、进程

程序:为完成某种功能,使用计算机语言编写的一系列指令集,也就是静态代码

进程:运行中的程序,计算机操作系统进行资源分配的最小单位

线程:是进程内部最小的执行单元,是操作系统进行任务调度的最小单元

2.进程与线程之间的关系

(1).一个进程包含多个线程,但一个线程只属于一个进程

(2).一个进程中必须有一个主线程,在主线程中可以创建其他子线程

    //main方法为主线程
    public static void main(String[] args) {
        //创建一个新的线程
        MyThread mThread=new MyThread();
        //mThread.test(); //直接调用新线程中的方法无法启动线程,相当于普通方法的调用
        mThread.start();  //启动新线程

        for(int i=0;i<1000;i++){
            System.out.println("主线程:"+i);
        }
    }

(3).一个进程中的线程可以共享该进程中的所有资源

3.Java中如何创建线程?
(1).创建一个类继承Thread类(该类属于线程类)
public class MyThread extends Thread{
    //创建新线程必须继承Thread类,重写run()方法,将线程中需要执行的内容写在run()中
    @Override
    public void run() {
        for(int i=0;i<1000;i++){
            System.out.println("新线程:"+i);
        }
    }
}
(2).创建一个类实现Runnable接口(该类不属于线程类)
public class RunTask implements Runnable{
    //创建一个任务执行类,实现Runnable接口,重写run()方法
    @Override
    public void run() {
        //需要执行的任务
        for(int i=0;i<200;i++){
            System.out.println("runtask:"+i);
        }
    }
}

public class Test {
    //创建主线程
    public static void main(String[] args) {
        RunTask task=new RunTask(); //创建一个任务执行的对象
        Thread thread=new Thread(task); //创建一个新的线程对象,添加需要执行的任务
        thread.start(); //启动新线程

        for(int i=0;i<200;i++){
            System.out.println("main:"+i);
        }
    }
}

Note:类实现Runnble接口,必须重写run()方法,将需要执行的任务写在run()中!

4.两种创建方式有什么区别?

(1).所创建的Thread子类不能再继承其他类(Java是单继承)

(2).创建一个类实现Runnable接口,该类还能再继承其他类

5.Thread类中的方法
run(); //写线程中需要执行的代码
start(); //启动线程
Thread thread-new Thread();  //创建一个线程
Thread thread=new Thread(task);  //创建一个线程并添加需要执行任务
Thread thread=new Thread(task,"MyThread1"); //在线程中添加需要执行的任务并为其设置线程名
thread.setName(String name);  //为线程设置线程名
thread.setPriority(int Priority); //为线程设置优先级,1-10
Thread.currentThread(); //获取当前正在执行的线程
Thread.currentThread().getName();  //返回当前正在执行的线程的名字
Thread.currentThread().getId();  //返回当前正在执行的线程的ID
Thread.currentThread().getPriority();  //返回当前正在执行的线程的优先级,默认为5
Thread.yield();  //线程让步,使线程从运行状态转为就绪状态
Thread.sleep();  //线程休眠指定时间,即线程从运行状态转为阻塞状态,不会释放锁,时间完后又转为就绪状态
Thread.join();  //线程加入,使其他线程先转为阻塞状态,等待该线程执行结束后再执行
wait();  //线程等待,使线程进入阻塞状态,自己无法唤醒,等待notify()或notifyAll()唤醒,等待过程中会自动释放锁
5.线程状态(线程生命周期)

在这里插入图片描述

6.守护线程

线程分为用户线程和守护线程

(1).守护线程的设置

DaemonThread dt=new DaemonThread();  //创建DaemonThread类的对象,该类实现Runnable接口
Thread thread=new Thread(dt);
thread.setDaemon(true);  //设置线程为守护线程,必须在线程启动之前进行设置
thread.start();
(2).作用:为其他线程提供服务
(3).特点:在系统中其他线程结束运行后,守护线程会自动结束运行,如JVM中的垃圾处理线程就是守护线程
7.多线程
(1).什么是多线程?

在一个程序中可以创建多个线程,执行不同的任务

(2).什么时候需要多线程?

程序需要同时执行多个任务时

(3).多线程的优点

提高程序的相应;提高CPU的利用率;改善程序的结构

(4).多线程的缺点

占用内存;

占用CPU资源,需要对多线程进行管理;

多个线程同时访问共享资源时,如果不加以控制,可能会出现线程安全问题

8.线程同步

对于线程安全问题,Java中引入了线程同步,通过对多个线程访问共享资源时进行加锁,使多个线程依次访问共享资源,从而避免出现线程安全问题

(1).并行与并发

并行:多个线程在同一时刻同时执行

并发:在一个时间段内,多个线程一次执行

(2).加锁方式

synchorized关键字修饰:

1>.修饰代码块时,需要创建同步对象(多个线程对应一个同步对象,用来记录是否有线程进入到同步代码块中)
对于Thread类的子类,如果创建多个子类对象(即创建了多个线程),在使用synchronized关键字对run()中需要执行的代码块进行修饰时,所创建的同步对象需要使用关键字static修饰,确保多个线程对应的是一个同步对象

//模拟购票案例
public class TicketThread1 extends Thread{
    static int num=10;  //票的数量(共享数据)
    static Object obj=new Object();  //锁对象使用static修饰
    @Override
    public void run() {
        while(true){
            //注意加锁的位置,在While循环内
            synchronized(obj){  
                //obj锁对象必须是同一个对象,记录每次执行的线程,每次只能一个线程进入执行
                if(num>0){
                    System.out.println(Thread.currentThread().getName()+":"+num);
                    num--;
                }
                else{
                    break;
                }
            }
        }
    }
}

public class Test1 {
    public static void main(String[] args) {
        TicketThread thread1=new TicketThread();  //创建了两个线程对象
        TicketThread thread2=new TicketThread();
        thread1.start();
        thread2.start();
    }
}

对于实现Runnable接口的任务类,由于多个线程对应一个任务,只需创建一个该任务类的对象,所以执行的多个线程对应的同步对象只有一个,即所创建的任务类的对象,用this表示

public class TicketTask implements Runnable{
    int num=10;
    @Override
    public void run() {
        while(true){
            synchronized(this){  //同步对象只有一个,为创建的该类的对象,用this表示
                if(num>0){
                    System.out.println(Thread.currentThread().getName()+":"+num);
                    num--;
                }
                if(num==0){
                    break;
                }
            }
        }
    }
}

public class Test {
    public static void main(String[] args) {
        TicketTask ticketTask=new TicketTask();  //只创建了一个任务类的对象
        Thread thread1=new Thread(ticketTask,"窗口1");
        Thread thread2=new Thread(ticketTask,"窗口2");
        thread1.start();
        thread2.start();
    }
}

2>.修饰方法时,不需要手动创建同步对象
锁的对象有两种:
修饰非静态方法时,锁对象默认为this

public class TicketThread implements Runnable{
    int num=10;
    public void run(){
        while(true){
            if(num==0){
                break;
            }
            else{
               printTicket();
            }
        }
    }

    public synchronized void printTicket(){  //synchronized修饰的方法为非静态方法,锁对象为this
        if(num>0){
            System.out.println(Thread.currentThread().getName()+":"+num);
            num--;
        }
    }
}

public class Test {
    public static void main(String[] args) {
        TicketThread ticketThread=new TicketThread();
        Thread thread1=new Thread(ticketThread,"窗口1");
        Thread thread2=new Thread(ticketThread,"窗口2");
        thread1.start();
        thread2.start();
    }
}

修饰静态方法时,锁对象默认为该类的Class对象

//购票案例
public class TicketThread extends Thread{
    static int num=10;  //共享数据
    @Override
    public void run() {
        while(true){
            if(num==0){
                break;
            }
            else{
                printTiket();
            }
        }
    }

    public static synchronized void printTiket(){ //synchronized修饰静态方法,锁对象是该类的Class对象,Class对象只有一个,实现了多个线程对应一个同步对象
        if(num>0){
            System.out.println(Thread.currentThread().getName()+":"+num);
            num--;
        }
    }
}

public class Test {
    public static void main(String[] args) {
        TicketThread thread1=new TicketThread();
        thread1.setName("窗口1");
        TicketThread thread2=new TicketThread();
        thread2.setName("窗口2");
        thread1.start();
        thread2.start();
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值