day-13-对线程【Thread、线程创建】

1.线程

一个线程就是一个正在运行的程序;就是程序执行的线路(路径);

如果程序中同时有两个或两个以上的程序在执行,这个程序叫做多线程程序;

进程:是应用程序的载体,当软件一运行起来的时候,系统就会给这个软件创建一个新的进程。一个应用程序(软件)对应一个进程;

一个进程里面可以包含多个线程,一个线程里面只能包含一个进程;

好处:

提高软件的运行效率(性能);

1.1 多线程程序运行的原理

在同一时刻只能有一个线程正在运行CPU。

CPU资源的调度方式:
    第一种:分时调度
        操作系统会给多个线程平均分配CPU的时间;
    第二种:抢占式调度
        根据线程的优先级分配CPU资源,优先级高的线程最先得到CPU资源;

2.开发多线程程序

运行main方法的线程叫做主线程;

开发多线程程序有两种方式:

1.继承Thread类
    构造方法:
        Thread():创建线程对象,线程名字有默认的;
        Thread(String name):使用执行的名字创建线程对象;
    成员方法:
        String getName():得到线程的名字;
        void run():运行现成的逻辑代码的;
        void start():开启线程,只是开启线程处于就绪状态,并不是运行线程,当操作系统给它分配CPU资源后才能处于运行状态调用run方法;
    格式:
        修饰符 class 类名 extends Thread{
                重写run方法(){
                    子线程执行的代码;
            }
        }

    使用子线程步骤:
        1.定义子线程类,继承父类Thread类,重写run方法;
        2.创建子线程对象;
        3.调用对象的stert()方法;
    得到线程的名字:
        Thread.currentThread():得到当前线程对象;
        String getName():得到线程的名字;
        一行代码搞定:
            Thread.currentThread().getName():得到线程的名字;

2.实现Runnable接口

    步骤:
        1.定义一个类,实现Runnable接口,重写run方法,这个中写子线程要执行的代码;  
        2.创建子任务对象;
        3.创建子线程对象:Thread t=new Thread(子任务对象);
        4.调用子线程对象的start方法;

两种方式的区别:

1.第一种方式把任务的代码与子线程的代码耦合带一起了,第二种方式 把任务的代码和子线程的代码分开了,解耦性强;
2.第一种方式继承了Thread类,具有继承的局限性,扩展性不强,第二种实现了接口,还可以继承其他父类,扩展性强;

3.非线程安全的问题

三子线程共卖100张票,出现了卖重复的票,第0张票,副票;

原因:

    多个线程在改变一个共享的数据时, 出现了某一个线程不想要的结果.

解决办法:

    保证修改共享数据的代码在同一时刻只能被一个线程执行,保证线程是同步的;


常用的方式有两种:

    1.使用同步代码块
        使用关键字syncronized修饰一个代码块:修改共享数据的代码;
        格式:
            syncronized(锁对象){
                    修改共享数据的代码;
                }

        同步:代码从上往下一行一行的执行;
        异步:多个线程同时执行;

        锁对象:

            用来锁住同步代码块的,只有获得这个锁对象的线程才能执行同步代码块,线程执行完同步代码块后,释放锁对象,然后其他线程才能得到锁对象;

示例代码:

public class TicketRunnable implements Runnable {

// 共享的100张票,可以让三个窗口(子线程)卖这100张票
        int ticketNumber = 100;
    // 作为锁对象
    Object obj = new Object();

            @Override
        public void run() {
            while (true) {

    // 只有获得obj对象的线程才能执行下面的代码.
    // synchronized(obj){
    // 可以使用this作为锁对象,因为三个线程使用的是同一个TicketRunnable对象,this就是TicketRunnable对象
        synchronized (this) {
            if (ticketNumber > 0) {
    // 让当前线程睡眠50毫秒.模拟网络延迟的时间
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                        e.printStackTrace();
                }
    System.out.println(Thread.currentThread().getName() + "正在卖第" + (ticketNumber--) + "张票");
                }
            }

        }
    }
}


2.使用同步方法

    格式:

    修饰符 syncronized 返回值类型 方法名(参数列表){
                    修改共享数据的代码;
                }

示例代码:

public class TicketRunnable implements Runnable {
// 共享的100张票,可以让三个窗口(子线程)卖这100张票
    int ticketNumber = 100;

        // 作为锁对象
    Object obj = new Object();

            @Override
    public  void run() {
        while(true){    
            //调用同步方法
            sell();
        }
    }

    // 同步方法使用的锁对象默认是this
    public synchronized void sell(){
        if(ticketNumber > 0){
    // 让当前线程睡眠50毫秒.模拟网络延迟的时间
            try {
                    Thread.sleep(50);
            }catch (InterruptedException e) {
                    e.printStackTrace();
            }
    System.out.println(Thread.currentThread().getName()+"正在卖第"+ (ticketNumber--) +"张票");
            }
        }
    }


3.lock锁接口

    Lock lock = new  ReentrantLock();

        // 获得锁对象
        lock.lock();
            同步代码块;
        //释放锁对象
        lock.unlock();

        同一时刻只能有一个

4.线程状态

新建状态:创建了线程对象后; 
就绪状态:调用start方法后;
运行状态:调用run方法后;
等待状态:锁对象正被其他线程使用,自己没有获得锁对象.
休眠状态:自己获得了锁对象,但是调用了自己的sleep方法,自己处于休眠状态.
结束(死亡)状态:run方法执行完毕后;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值