Thread线程API及线程安全锁

第一种开启线程的方式

1.定义一个类继承Thread类

2.重写run方法(线程任务:线程将执行的内容)

3.开启线程

        创建子类对象

        调用start方法

//定义个类,继承线程Thread
public class MyThread extends Thread {


    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            System.out.println("sub..."+i);
        }
    }
}
public class Test {
    public static void main(String[] args) {
        MyThread mt = new MyThread();

        mt.start();


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

    }
}

为什么要开启线程继承Thread类?

因为Thread类就是线程类,具备线程应该有的所有功能,继承了Thread类,就是线程类

就可以使用Thread类里面所有的功能.例如 start方法

第二种创建方法

1.定义实现类实现Runnable接口

2.重写run方法 (线程任务)

3.开启线程

        创建Runnable接口的实现类对象

        创建Thread类对象,将实现类对象传入

        调用Thread类的start方法,开启线程

Thread类构造方法

public Thread(Runnable r)

方法的参数是接口,可以传入任意实现类对象

跟第一种就是,一个继承,一个实现,但重写的方法都是一样的,就没有代码示例了.

思考:为什么有了第一种方式,为什么还会有第二种方式?

1.避免了java单继承的局限性,一个类如果有了父类,是没有办法通过继承Thread类的方式开启线程的,但java是多实现的,所以此时可以通过实现接口的方式来开启线程

2.将线程任务与对象分离 降低了耦合性

        第一种方式        将线程任务和线程对象耦合到了一起,创建对象,既是线程对象也包括了线程任务

        第二种方式        线程对象和线程任务是分开创建的,降低了耦合性

3.更符合面向对象思想 更容易实现 多条线程共用一个任务

调用run方法和start方法的区别 

如果调用run方法,那么run方法会到主线程的栈区去执行  依旧是个单线程程序

如果调用start方法 那么jvm会开启一条新的线程 并调用run方法 在新线程中执行   多线程程序

API

static void sleep(long time)        当前线程睡眠time毫秒后 醒来继续执行

setName/getName  设置与获取线程名字

当当前类不是线程的子类时,可以调用Thread的静态方法currentThread(),用来获取当前线程对象,然后就可getName();

线程的优先级,设置了也不一定先执行完毕.

public static final int MIN_PRIORITY   //1 最低优先级
public static final int NORM_PRIORITY  //5 默认优先级
public static final int MAX_PRIORITY   //10 最大优先级

设置守护线程        用户线程执行完毕,守护线程无论执行怎样,jvm直接退出

public final void setDaemon(Boolean on) on的值为true时将当前线程设置为守护线程,注意一定要在线程开启前设置

线程等待 join

void join()  让当前线程等待 让调用方法的线程插队 调用方法的线程执行完毕后,当前线程才继续执行,对其他的线程没有影响

线程停止

void stop() 直接杀死对应的线程        直接结束,有点不友好

void interrupt()  中断线程

boolean isInterrupt()  返回true则线程中断,false没有

这种比较友好,中断线程后,可以利用返回的布尔值对代码进行进一步操作

线程安全问题

当多条线程共享一个资源时,有可能出现数据错误,导致线程不安全

解决方法:

        线程同步        关键词synchronized  对象监视器

        lock锁

线程同步

        同步代码块

        synchronized(任意对象){

        有可能出现问题的代码

}

      同步方法

        在方法的返回之前加上 synchronized

?

同步方法有锁吗?        有的,是当前对象  this

同步方法可以是静态的吗?    可以,锁就不是this了,因为静态中不能使用this/super

静态的同步方法  锁对象时谁?        当前类名.class

Lock锁

方法

void lock()   获取锁

void unLock()   释放锁

常用实现类

        java.util.concurrent.locks.ReentrantLock

示例:

public class SellTickets implements Runnable {

    private int i = 100;
    
    //创建lock锁实现类对象
    private Lock l = new ReentrantLock();

    @Override
    public void run() {



        while(true){

            l.lock();

                if(i>0){

                    try {
                        Thread.sleep(100);

                        System.out.println(Thread.currentThread().getName()+"卖票了..."+i);
                        i--;
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }finally {

                        l.unlock();
                    }
                }else{
                    l.unlock();
                }

            }

    }
}

Object类的线程方法

void wait()       当前线程等待 此方法必须由对象监视器调用   哪个对象监视器调用了这个方法  线程就在哪个对象监视器上等待

void notify()        唤醒正在当前对象监视器上等待的线程  中的一个线程

wait和notify方法必须在同步中使用  必须都由锁对象(对象监视器)来调用

wait和sleep的区别

        sleep方法是Thread类的方法  睡眠n毫秒后  自动醒来继续执行代码,既可以在同步外使用,也可以在同步中使用,在同步中使用时,锁不会被释放掉

        wait方法是Object类的方法   线程遇到wait方法进入到等待状态,必须由其他线程唤醒才能执行,其必须在同步中使用,且等待时,还会将锁释放掉

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值