多线程的学习

一、线程的创建

线程的创建方式1:通过继承Thread的方式

        (1)创建一个继承于Thread的子类

        (2)重写Thread的run()方法

        (3)在main方法中创建子类的对象

        (4)通过此对象调用start()方法 ①启动当前线程 ②调用当前线程的run()方法

注意:

不能通过对象直接调用run方法,需要调用start方法

再启动一个线程不能只创建一个对象,需要再创建一个线程的对象,再调用start方法

Thread类中的一些方法:

1、start()方法:启动当前线程的run()

2、run()方法:通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中

3、currentThread():静态方法,返回执行当前代码的线程

4、getName():获取当前线程的名字

5、setName():设置当前线程的名字

6、yield():调用此方法的线程释放当前CPU的执行权

7、join():在线程a中调用此方法,线程a就会进入阻塞状态,直到其他线程执行完之后,才会执行线程a

8、stop():已经过时了,直接结束当前线程

9、sleep():让当前方法“睡眠”指定的millitime:毫秒数 。在指定的毫秒时间内,当前线程是阻塞状态,此方法会出现异常处理,只能用try-catch去处理,不能抛出异常

10、isAlive():判断当前线程是否存活

线程的优先级:

说明:高优先级的线程抢占低优先级CPU的执行权,但是只是从概率上讲,高优先级的线程高概率的情况下被执行。并不意味着只有当高优先级的执行完,低优先级的才能执行

1、

MAX_PRIORITY:10

MIN_PRIORITY:1

NORM_PRIORITY:5

2、如何获取和设置当前线程的优先级

getPriority()

setPriority()

线程的创建方式2:实现Runnable接口的方式

1、创建一个实现Runnable接口的类

2、实现类去实现Runnable接口中的方法run()

3、创建实现类的对象

4、将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象

5、通过Thread类的对象调用start方法


 

线程的创建方式3:实现Callable接口

和实现Runnable()方式相比,Callable功能更强大

1、创建Callable接口的实现类,并重写call()方法,call方法中声明的是需要执行的操作

①此方法有返回值

②方法可以抛出异常

③支持泛型返回值

④需要借助FutureTask类,比如获取返回结果

2、创建一个重写call()方法类的实例

例:NewThread newThread = new NewThread();

3、创建一个FutureTask类的对象,并将2的实例放进去

FutureTask task = new FutureTask(newThread);

4、创建Thread类的实例,并将task放进去

Thread thread = new Thread(task);

5、使用thread调用start方法,启动线程

thread.start();

线程的创建方式4(开发中最常用的):使用线程池

1、使用工具类Executors,提供指定线程数量的线程池

ExecutorSercive servive = Executors.newFixedThreadPool(10);

好处:

①提高响应速度

②降低资源消耗

③便于线程管理

2、可调用的两个方法

service.execute();//适合适用于Runnable,括号里面传入一个实现了Runnable接口的实现类

service.submit();//适合使用Callable,括号里面传入一个实现了Callable接口的实现类

二、第一种方式和第二种方式的对比

开发中:优先选择:实现Runnable接口的方式

原因:1、实现的方式没有类的单继承的局限性

           2、实现的方式更适合来处理多个线程有共享数据的情况

联系:Thread类也实现了Runnable接口

相同点:两种方式都需要重写run方法

三、线程的生命周期

新建:

        新建——>就绪:调用start()进入就绪状态

就绪:

        就绪——>运行:得到CPU的执行权会进入运行状态

运行:

        运行——>就绪:失去CPU的执行权或调用yield()方法会进入就绪状态,

        运行——>死亡:执行完run()方法会进入死亡状态或者调用stop()方法;出现异常Error/Exception并且没处理

        运行——>阻塞:执行sleep(long time)方法,join()方法,等待同步锁,wait()方法,suspend()方法(已经过时)

阻塞:

        阻塞——>就绪:sleep()时间到,join()结束,获取同步锁,notify()/notifyAll(),resume()

死亡:结束

四、线程的安全

1、同步代码块

        synchronized(同步监视器){

                //需要被同步的代码

        }

        说明:从操作共享数据的代码,即为需要被同步的代码

        共享数据:多个线程共同操作的变量。

        同步监视器:俗称:锁。任何一个类的对象,都可以充当锁,

        要求:多个线程必须要用同一把锁。

        同步的方式,解决了线程的安全问题。-----好处

        操作同步代码时,只能有一个线程参与,其他线程等待。相当于是一个单线程的过程,效率低。

2、同步方法

        用synchronized关键字修饰的方法

        总结:1、同步方法仍然涉及到同步监视器,只是不需要我们显示的声明

                2、非静态的同步,同步监视器:this

                3、静态的同步方法,同步监视器是:当前类本身

3、使用同步锁

①创建同步锁实例,实例化ReentrantLock

private ReentrantLock lock = new ReentrantLock();

②、调用里面方法,锁住线程

lock.lock();

③调用里面方法,释放锁

lock.unlock();放在finally中,保证一定能执行

五、线程通信

三个方法:

①wait():一旦执行了此方法,当前线程就会进入阻塞状态

②notify():一旦执行了此方法,就会唤醒wait的一个线程。如果有多个线程,先唤醒优先级高的

③notifyAll():一旦执行了此方法,会唤醒所有wait的线程

说明:

三个方法必须在同步代码块或者同步方法中

三个方法的调用者必须是同步代码块或者同步方法中的同步监视器,否则会出现异常IllegalMonitorStateException()

三个方法时定义在Object类中的,而不是Thread类中

六、重要面试题

1、sleep()和wait()方法的异同?

相同点:一旦执行了这两个方法,都会使线程进图阻塞状态

不同点:

①两个方法声明的位置不同:Thread类中声明sleep(),Object类中声明wait()

②调用的要求不同:sleep()可以在任何需要的场景下调用。wait()只能在同步代码块或者同步方法中

③关于释放锁的问题:调用wait()会释放锁,而sleep()不会释放锁

2、生产者消费者问题(线程通信的应用 )

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值