java线程

当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态。在线程的生命周期中,它要经过新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)五种状态。尤其是当线程启动以后,它不能一直“霸占”着CPU独自运行,所以CPU需要在多条线程之间切换,于是线程状态也会多次在运行、阻塞之间切换。

生命周期的五种状态

1.新建(new Thread)

当创建Thread类的一个实例(对象)时,此线程进入新建状态(未被启动)。

例如:

Thread  t1=new Thread();

2.就绪(runnable)

线程已经被启动,正在等待被分配给CPU时间片,也就是说此时线程正在就绪队列中排队等候得到CPU资源

例如:

t1.start();

3.运行(running)

线程获得CPU资源正在执行任务(run()方法),此时除非此线程自动放弃CPU资源或者有优先级更高的线程进入,线程将一直运行到结束。

4.堵塞(blocked)

由于某种原因导致正在运行的线程让出CPU并暂停自己的执行,即进入堵塞状态。

正在睡眠:用sleep(long t) 方法可使线程进入睡眠方式。一个睡眠着的线程在指定的时间过去可进入就绪状态。

正在等待:调用wait()方法。(调用motify()方法回到就绪状态)

被另一个线程所阻塞:调用suspend()方法。(调用resume()方法恢复)

5.死亡(dead)

当线程执行完毕或被其它线程杀死,线程就进入死亡状态,这时线程不可能再进入就绪状态等待执行。

自然终止:正常运行run()方法后终止

异常终止:调用stop()方法让一个线程终止运行

线程创建

1、继承Thread

public class MyThread extends  Thread{
     public  void  run(){
         System.out.println("----------------执行线程----------------");
    }
}
  public static void main(String[] args) {
        MyThread myThread1 = new MyThread();
        MyThread myThread2=new MyThread();
        myThread1.start();
        myThread2.start();
    }

2.实现Runnable接口

public class MyThread2 implements  Runnable{
    @Override
    public void run() {
        System.out.println("----------------执行线程2----------------");
    }
}

//实现Runnable接口的方式实现多线程,并且实例化Thread,传入自己的Thread实例,调用run( )方法
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        Thread thread=new Thread(myThread);
        thread.start();
    }

一般应用场景线程

1.定时器来开启后台线程处理,比如有些数据表的状态我需要定时去修改、我们搜索引擎里面的数据需要定时去采集、定时生成统计信息、定时清理上传的垃圾文件等
2.异步处理
3.分布式计算

什么是线程池,如何使用?

线程池就是事先将多个线程对象放到一个容器中,当使用的时候就不用new线程而是直接去池中拿线程即可,节省了开辟子线程的时间,提高的代码执行效率。

常用的线程池有哪些?

newSingleThreadExecutor:创建一个单线程的线程池,此线程池保证所有任务的执行顺序按照任务的提交顺序执行。

newFixedThreadPool:创建固定大小的线程池,每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。

newCachedThreadPool:创建一个可缓存的线程池,此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。

newScheduledThreadPool:创建一个大小无限的线程池,此线程池支持定时以及周期性执行任务的需求。

newSingleThreadExecutor:创建一个单线程的线程池。此线程池支持定时以及周期性执行任务的需求。

启动一个线程是调用 run()方法还是 start()方法?

启动一个线程是调用 start()方法,使线程所代表的虚拟处理机处于可运行状态,这意味着它可以由 JVM
调度并执行,这并不意味着线程就会立即运行。 run()方法是线程启动后要进行回调(callback)的方法。

总结

1.wait():使一个线程处于等待(阻塞)状态,并且释放所持有的对象的锁;
2.sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要处理InterruptedException异常;
3.notify():唤醒一个处于等待状态的线程,当然在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,
而是由JVM确定唤醒哪个线程,而且与优先级无关;
4.notityAll():唤醒所有处于等待状态的线程,该方法并不是将对象的锁给所有线程,而是让它们竞争,只有获得锁 的线程才能进入就绪状态;
注意:java 5 通过Lock接口提供了显示的锁机制,Lock接口中定义了加锁(lock()方法)和解锁(unLock()
方法),增强了多线程编程的灵活性及对线程的协调

死锁

死锁的定义:所谓死锁是指多个线程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进

synchronized 和 volatile 关键字的作用

一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:
1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是 立即可见的。 2)禁止进行指令重排序。
volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取;
synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
1.volatile仅能使用在变量级别; synchronized则可以使用在变量、方法、和类级别的
2.volatile仅能实现变量的修改可见性,并不能保证原子性; synchronized则可以保证变量的修改可见性和原子性
3.volatile不会造成线程的阻塞; synchronized可能会造成线程的阻塞。
4.volatile标记的变量不会被编译器优化; synchronized标记的变量可以被编译器优化

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值