JUC总结1

线程和进程的对比

进程是操作系统资源分配的最小单位,其包含了进程控制块、程序、数据等,在电脑上启动的一个个应用程序就是进程,当一个程序要被运行时,从磁盘中将这个应用程序的代码加载到内存中,就开启了一个进程。

线程是调度的基本单位,即CPU资源分配的基本单位,一个进程中包含了多个线程,如Java程序启动后,会开启一个main线程。

对于不同的进程,使用不同的内存空间,而同一进程中的线程,共享内存空间。对于同一个进程中线程的上下文切换,比进程上下文切换效率更高。

线程创建的方式

1、继承Thread类,重写run方法,启动线程时调用start方法(注意run方法返回值为void,不能改成其他类型);

2、调用Runnable接口,重写run方法,创建Thread类,并在创建Thread类时,将调用了Runnable接口的类作为参数进行传入,要启动线程则要通过所创建的Thread类调用start方法。

3、调用Callable接口,并重写call方法,其中call方法有返回值,且为泛型,需要指定返回的类型,调用Callable时也需指定类型。要启动线程,首先需创建调用了Callable接口的对象,并将所创建的对象作为参数创建FutureTask,其中FutureTask需指定类型,该类型即为call方法返回值的类型,最后传入所创建的FutureTask对象创建Thread对象,通过start方法调用,大致流程代码如下:

 CallableTask task = new CallableTask();//CallableTask实现了Callable接口
 FutureTask<String> futureTask = new FutureTask<>(task);
 Thread thread = new Thread(futureTask);
 thread.start();

4、线程池创建,通过Executors.newFixedThreadPool(n)定义一个大小为n的线程池,得到ExecutorService对象,然后通过调用submit方法启动线程,其中在调用submit方法时,需要传入实现了Runnale接口的类,可通过shutdown方法关闭线程池。

Runnale和Callable对比

1、Runnale中的run方法无返回值,而Callable中的call方法有返回值且是泛型;

2、Callable方法支持返回执行的结果,通过FutureTask.get方法来获取,此方法会阻塞正在执行的线程,若不调用则不会阻塞;

3、Callable的call方法可以抛出异常,而Runnable的run方法不能抛出,只能内部消化。

start和run方法的区别

当调用start方法时,会创建一个新的线程,执行run方法,run方法在新线程中执行,从而达到了多线程的效果;如果直接调用run方法,则run方法在当前线程中执行,不能实现多线程。run方法可被调用多次,而start方法只能被调用一次。

线程的各种状态

1、NEW:初始状态,此时线程被创建但未调用start方法启动,此时未与操作系统底层的线程产生联系;

2、Runnale:运行状态,包含了READY就绪、RUNNING运行中两种状态,其中对于就绪状态的线程,可通过系统调度的方式将线程转化为运行中状态,对于运行中的线程,可通过系统调用或yield方法将其转化为就绪状态。

3、BLOCKED:阻塞状态,当线程获取锁失败时,会进入阻塞状态,此时线程不占用cpu资源。当其他线程释放锁时,会按照一定的规则从阻塞队列中唤醒线程,被唤醒的线程进入运行状态。

4、WAITING:等待状态,该状态的线程需要等待其他线程做出特定动作,此时线程不占用cpu资源。当其他持有锁的线程调用notify或notifyAll方法时,会按一定的规则唤醒处于等待状态的线程,对于运行状态的线程,可通过调用Thread.join()、Thread.wait()方法进入等待状态。

5、TIME_WAITING:超时等待,与等待状态不同,该状态的线程会在一定时间后返回,该状态的线程不占用cpu资源。处于运行状态的线程,可通过调用Object.sleep(time)、Thread.join(time)、Thread.wait(time)这些指定时间的方法进入等待状态,当时间到后线程转化为运行状态,当其他持有锁的线程调用notify或notifyAll方法时,会按一定的规则唤醒这些处于等待状态的线程。

6、TERMINATED:终止状态,线程执行结束后会进入该状态。

保证线程执行顺序方法

可通过join关键字,保证多个线程的执行顺序性,如下列代码:

Thread t = new Thread(()->{
    try {
        t1.join(); 
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("1");
});

代码中的t1.join()表示线程t需要在t1执行结束后才能执行。

sleep和wait对比

使用sleep、wait均可以使线程暂时放弃cpu,进入阻塞状态,线程执行sleep、wait在等待期间若被中断,则会抛出InterruptedException异常

但也有以下不同:

1、sleep属于Thread类,wait属于Object类;

2、执行sleep(long)、wait(long)的线程可在指定的时间被唤醒,其中wait(long)可被notify或notifyAll方法唤醒,而wait()方法如果不被唤醒,则会一直等待下去;

3、线程执行wait方法后会释放锁,执行sleep方法后不会释放锁;

4、sleep方法可在任意地方被调用,wait方法使用的前提是当前线程必须持有对该对象的锁,必须在同步方法或同步代码块中执行,否则会抛出IllegalMonitorStateException异常。

如何终止线程

1、使用退出标识,线程在run方法执行结束后正常退出;

2、使用stop方法强行停止,但这种方法不推荐,因为 stop 方法会导致线程立即停止,可能会在不一致的状态下释放锁,破坏对象的一致性,导致难以发现的错误和资源泄漏;

3、使用interrupt方法,对于线程t,执行代码t.interrupt(),可终止线程t。同时isInterrupted方法可检查当前线程是否中断,interrupted方法可在检查线程是否被中断的同时,在线程被中断的情况下清除中断标志。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值