Java高并发编程四

做个笔记,java线程常用的方法,耐心看完.

编号

方法

说明

1

public void start()

使该线程开始执行;Java 虚拟机调用该线程的 run 方法。

2

public void run()

如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。

3

public final void setName(String name)

改变线程名称,使之与参数 name 相同。

4

public final void setPriority(int priority)

更改线程的优先级。

5

public final void setDaemon(boolean on)

将该线程标记为守护线程或用户线程。

6

public final void join(long millisec)

等待该线程终止的时间最长为 millis 毫秒。

7

public void interrupt()

中断线程。

8

public final boolean isAlive()

测试线程是否处于活动状态。

9

public static void yield()

暂停当前正在执行的线程对象,并执行其他线程。

10

public static void sleep(long millisec)

在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。

11

public static Thread currentThread()

返回对当前正在执行的线程对象的引用。

一.静态方法

1.currentThread()方法

currentThread()方法可以返回代码段正在被哪个线程调用的信息。

1public class Run1{ 2 public static void main(String[] args){ 3 System.out.println(Thread.currentThread().getName()); 4 } 5}

2.sleep()方法

方法sleep()的作用是在指定的毫秒数内让当前“正在执行的线程”休眠(暂停执行)。这个“正在执行的线程”是指this.currentThread()返回的线程。

sleep方法有两个重载版本:

1sleep(long millis) //参数为毫秒 2sleep(long millis,int nanoseconds) //第一参数为毫秒,第二个参数为纳秒

sleep相当于让线程睡眠,交出CPU,让CPU去执行其他的任务。
但是有一点要非常注意,sleep方法不会释放锁,也就是说如果当前线程持有对某个对象的锁,则即使调用sleep方法,其他线程也无法访问这个对象。看下面这个例子就清楚了:

1public class Test { 2 3 private int i = 10; 4 private Object object = new Object(); 5 6 public static void main(String[] args) throws IOException { 7 Test test = new Test(); 8 MyThread thread1 = test.new MyThread(); 9 MyThread thread2 = test.new MyThread(); 10 thread1.start(); 11 thread2.start(); 12 } 13 14 class MyThread extends Thread{ 15 @Override 16 public void run() { 17 synchronized (object) { 18 i++; 19 System.out.println("i:"+i); 20 try { 21 System.out.println("线程"+Thread.currentThread().getName()+"进入睡眠状态"); 22 Thread.currentThread().sleep(10000); 23 } catch (InterruptedException e) { 24 // TODO: handle exception 25 } 26 System.out.println("线程"+Thread.currentThread().getName()+"睡眠结束"); 27 i++; 28 System.out.println("i:"+i); 29 } 30 } 31 } 32}

从上面输出结果可以看出,当Thread-0进入睡眠状态之后,Thread-1并没有去执行具体的任务。只有当Thread-0执行完之后,此时Thread-0释放了对象锁,Thread-1才开始执行。

注意,如果调用了sleep方法,必须捕获InterruptedException异常或者将该异常向上层抛出。当线程睡眠时间满后,不一定会立即得到执行,因为此时可能CPU正在执行其他的任务。所以说调用sleep方法相当于让线程进入阻塞状态。

3.yield()方法

调用yield方法会让当前线程交出CPU权限,让CPU去执行其他的线程。它跟sleep方法类似,同样不会释放锁。但是yield不能控制具体的交出CPU的时间,另外,yield方法只能让拥有相同优先级的线程有获取CPU执行时间的机会。

注意,调用yield方法并不会让线程进入阻塞状态,而是让线程重回就绪状态,它只需要等待重新获取CPU执行时间,这一点是和sleep方法不一样的。
代码:

1public class MyThread extends Thread{ 2 @Override 3 public void run() { 4 long beginTime=System.currentTimeMillis(); 5 int count=0; 6 for (int i=0;i<50000000;i++){ 7 count=count+(i+1); 8 //Thread.yield(); 9 } 10 long endTime=System.currentTimeMillis(); 11 System.out.println("用时:"+(endTime-beginTime)+" 毫秒!"); 12 } 13} 14 15public class Run { 16 public static void main(String[] args) { 17 MyThread t= new MyThread(); 18 t.start(); 19 } 20} 21//用时:3 毫秒! 22//如果将 Thread.yield();的注释去掉,执行结果如下: 23用时:16080 毫秒!

二.对象方法

1.start()方法

start()用来启动一个线程,当调用start方法后,系统才会开启一个新的线程来执行用户定义的子任务,在这个过程中,会为相应的线程分配需要的资源。

2.run()方法

run()方法是不需要用户来调用的,当通过start方法启动一个线程之后,当线程获得了CPU执行时间,便进入run方法体去执行具体的任务。注意,继承Thread类必须重写run方法,在run方法中定义具体要执行的任务。

3.getId()

getId()的作用是取得线程的唯一标识
 

1public class Test { 2 public static void main(String[] args) { 3 Thread t= Thread.currentThread(); 4 System.out.println(t.getName()+" "+t.getId()); 5 } 6} 7//main 1

4.isAlive()方法

方法isAlive()的功能是判断当前线程是否处于活动状态
 

1public class MyThread extends Thread{ 2 @Override 3 public void run() { 4 System.out.println("run="+this.isAlive()); 5 } 6} 7public class RunTest { 8 public static void main(String[] args) throws InterruptedException { 9 MyThread myThread=new MyThread(); 10 System.out.println("begin =="+myThread.isAlive()); 11 myThread.start(); 12 System.out.println("end =="+myThread.isAlive()); 13 } 14} 15 16//begin ==false 17//run=true 18//end ==false

方法isAlive()的作用是测试线程是否偶处于活动状态。什么是活动状态呢?活动状态就是线程已经启动且尚未终止。线程处于正在运行或准备开始运行的状态,就认为线程是“存活”的。
有个需要注意的地方

System.out.println("end =="+myThread.isAlive());

虽然上面的实例中打印的值是true,但此值是不确定的。打印true值是因为myThread线程还未执行完毕,所以输出true。如果代码改成下面这样,加了个sleep休眠:

1public static void main(String[] args) throws InterruptedException { 2 MyThread myThread=new MyThread(); 3 System.out.println("begin =="+myThread.isAlive()); 4 myThread.start(); 5 Thread.sleep(1000); 6 System.out.println("end =="+myThread.isAlive()); 7 }

则上述代码运行的结果输出为false,因为mythread对象已经在1秒之内执行完毕。

5.join()方法

在很多情况下,主线程创建并启动了线程,如果子线程中药进行大量耗时运算,主线程往往将早于子线程结束之前结束。这时,如果主线程想等待子线程执行完成之后再结束,比如子线程处理一个数据,主线程要取得这个数据中的值,就要用到join()方法了。方法join()的作用是等待线程对象销毁。

1public class Thread4 extends Thread{ 2 public Thread4(String name) { 3 super(name); 4 } 5 public void run() { 6 for (int i = 0; i < 5; i++) { 7 System.out.println(getName() + " " + i); 8 } 9 } 10 public static void main(String[] args) throws InterruptedException { 11 // 启动子进程 12 new Thread4("new thread").start(); 13 for (int i = 0; i < 10; i++) { 14 if (i == 5) { 15 Thread4 th = new Thread4("joined thread"); 16 th.start(); 17 th.join(); 18 } 19 System.out.println(Thread.currentThread().getName() + " " + i); 20 } 21 } 22} 23/* 24main 0 25main 1 26main 2 27main 3 28main 4 29new thread 0 30new thread 1 31new thread 2 32new thread 3 33new thread 4 34joined thread 0 35joined thread 1 36joined thread 2 37joined thread 3 38joined thread 4 39main 5 40main 6 41main 7 42main 8 43main 9 44由上可以看出main主线程等待joined thread线程先执行完了才结束的。如果把th.join()这行注释掉,运行结果如下: 45main 0 46main 1 47main 2 48main 3 49main 4 50main 5 51main 6 52main 7 53main 8 54main 9 55new thread 0 56new thread 1 57new thread 2 58new thread 3 59new thread 4 60joined thread 0 61joined thread 1 62joined thread 2 63joined thread 3 64joined thread 4 65*/ 66

6.getName和setName

用来得到或者设置线程名称。

7.getPriority和setPriority

用来获取和设置线程优先级。此方法不常用,这种方式不可靠

8.setDaemon和isDaemon

用来设置线程是否成为守护线程和判断线程是否是守护线程。

守护线程和用户线程的区别在于:守护线程依赖于创建它的线程,而用户线程则不依赖。举个简单的例子:如果在main线程中创建了一个守护线程,当main方法运行完毕之后,守护线程也会随着消亡。而用户线程则不会,用户线程会一直运行直到其运行完毕。在JVM中,像垃圾收集器线程就是守护线程。

三.面试题

1.线程和进程有什么区别?

    答:一个进程是一个独立(self contained)的运行环境,它可以被看作一个程序或者一个应用。而线程是在进程中执行的一个任务。线程是进程的子集,一个进程可以有很多线程,每条线程并行执行不同的任务。不同的进程使用不同的内存空间,而所有的线程共享一片相同的内存空间。别把它和栈内存搞混,每个线程都拥有单独的栈内存用来存储本地数据。

2.如何在Java中实现线程?

答:创建线程有两种方式:
一、继承 Thread 类,扩展线程。
二、实现 Runnable 接口。

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

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

4.Thread类的sleep()方法和对象的wait()方法都可以让线程暂停执行,它们有什么区别?

答:sleep()方法(休眠)是线程类(Thread)的静态方法,调用此方法会让当前线程暂停执行指定的时间,将执行机会(CPU)让给其他线程,但是对象的锁依然保持,因此休眠时间结束后会自动恢复。wait()是Object类的方法,调用对象的wait()方法导致当前线程放弃对象的锁(线程暂停执行),进入对象的等待池(wait pool),只有调用对象的notify()方法(或notifyAll()方法)时才能唤醒等待池中的线程进入等锁池(lock pool),如果线程重新获得对象的锁就可以进入就绪状态。

5.线程的sleep()方法和yield()方法有什么区别?

答:
① sleep()方法给其他线程运行机会时不考虑线程的优先级,因此会给低优先级的线程以运行的机会;yield()方法只会给相同优先级或更高优先级的线程以运行的机会;
② 线程执行sleep()方法后转入阻塞(blocked)状态,而执行yield()方法后转入就绪(ready)状态;
③ sleep()方法声明抛出InterruptedException,而yield()方法没有声明任何异常;
④ sleep()方法比yield()方法(跟操作系统CPU调度相关)具有更好的可移植性。

6.请说出与线程同步以及线程调度相关的方法。

  • wait():使一个线程处于等待(阻塞)状态,并且释放所持有的对象的锁;
  • sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要处理InterruptedException异常;
  • notify():唤醒一个处于等待状态的线程,当然在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且与优先级无关;
  • notityAll():唤醒所有处于等待状态的线程,该方法并不是将对象的锁给所有线程,而是让它们竞争,只有获得锁的线程才能进入就绪状态;

小伙伴一起加油吧

博主主页

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

Java日期时间API系列31

  时间戳是指格林威治时间1970年01月01日00时00分00秒起至现在的总毫秒数,是所有时间的基础,其他时间可以通过时间戳转换得到。Java中本来已经有相关获取时间戳的方法,Java8后增加新的类Instant等专用于处理时间戳问题。 1获取时间戳的方法和性能对比1.1获取时间戳方法Java8以前