线程的基本操作
来源:互联网 发布:数字音效软件 编辑:程序博客网 时间:2024/06/05 06:12
线程的基本操作
新建线程
java中建立线程可以有两种方式,分别是继承Thread类和实现Runnable接口。
public static class CreateThread extends Thread{ @Override public void run() { System.out.println("Oh, I am CreateThread"); }}public class CreateThread implements Runnable { @Override public void run() { System.out.println("Oh, I am Runnable"); }}
开启线程
开启线程的方式分为两种start(),run()
Thread t1 = new Thread();t1.start()Thread t2 = new Thread();t2.run()
两者的区别为:
start()是开启一个新的线程并执行run()函数,run()只在当前线程之中串行执行run()的代码。
终止线程
通常情况线程执行完毕后就会结束,不需要手动关闭,例如绝大部分的worker类型的线程。但是有些服务端的后台线程会常驻系统(死循环方式)。
JDK中提供了Thread.stop()方法,不过是一个废弃的方法,原因是:stop()方法过于暴力,强行把执行到一半的线程终止,可能会引起一些数据不一致的问题。例如:Thread.stop()方法在结束线程的时候,会直接终止线程,并且会立即释放这个线程所持有的锁。而这些锁恰恰是用来维持对象一致性的。
更好的结束线程的方式是使用一个变量标识是否需要结束,或者使用中断的方式:
//每次都是执行完一个循环体之后再退出//线程何时退出由程序员决定public static class ChangeObjectThread extends Thread { volatile boolean stopme = false; public void stopMe(){ stopme = true; } @Override public void run() { while (true) { if (stopme){ System.out.println("exit by stop me"); break; } //do something } }}//这里使用了中断判定来退出public static class ChangeObjectThread extends Thread { @Override public void run() { while (true) { if (Thread.currentThread().isInterrupted()){ System.out.println("exit with interrupted"); break; } //do something } }}
线程中断
与线程中断有关的,有三个方法:
public void Thread.interrupt() //中断线程public boolean Thread.isInterrupted() //判断是否被中断public static boolean Thread.interrupted() //判断是否被中断,并清除中断标志,static
public static void main(String[] args) throws InterruptedException { Thread t1=new Thread(){ @Override public void run(){ while(true){ // if(Thread.currentThread().isInterrupted()){ // System.out.println("Interruted!"); // break; // } Thread.yield(); } } }; t1.start(); Thread.sleep(2000); t1.interrupt();}
在这里虽然对t1进行了中断,但是在t1中并没有中断处理的逻辑(注释部分),因此即使t1线程被设置了中断状态,但是这个中断不会发生任何作用。
等待(wait)和通知(notify)
为了支持多线程之间的协作,JDK提供了两个非常重要的接口线程等待wait()方法和通知notify()\notifyAll()方法。这两个方法并不是在Thread类中的,而是输出Object类。
这也意味着任何对象都可以调用这两个方法。
public class SimpleWN { final static Object object = new Object(); public static class T1 extends Thread{ public void run() { synchronized (object) { System.out.println(System.currentTimeMillis()+":T1 start! "); try { System.out.println(System.currentTimeMillis()+":T1 wait for object "); object.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(System.currentTimeMillis()+":T1 end!"); } } } public static class T2 extends Thread{ public void run() { synchronized (object) { System.out.println(System.currentTimeMillis()+":T2 start! notify one thread"); object.notify(); System.out.println(System.currentTimeMillis()+":T2 end!"); try { Thread.sleep(2000); } catch (InterruptedException e) { } } } } public static void main(String[] args) { Thread t1 = new T1() ; Thread t2 = new T2() ; t1.start(); t2.start(); }}
上述的代码如果去除掉synchronized块,代码将无法运行。因为出现了java.lang.IllegalMonitorStateException。
首先,这儿要非常注意的几个事实是:
1)任何一个时刻,对象的控制权(monitor)只能被一个线程拥有。无论是执行对象的wait、notify还是notifyAll方法,必须保证当前运行的线程取得了该对象的控制权(monitor)
2)如果在没有控制权的线程里执行对象的以上三种方法,就会报java.lang.IllegalMonitorStateException异常。
3)JVM基于多线程,默认情况下不能保证运行时线程的时序性
基于以上几点事实,我们需要确保让线程拥有对象的控制权。也就是说在T1中执行wait方法时,要保证T1对object有控制权;在T2中执行notify方法时,要保证T2对object有控制权。
挂起(suspend)和继续执行(resume)线程
suspend()和resume()是一对相反的操作,在JDK中已经是废弃的方法。不推荐suspend()去挂起线程的原因是因为suspend()在导致线程暂停的同时,并不会去释放任何资源。
更为严重的是如果resume()在suspend()之前就执行了,那么被挂起的线程可能很难有机会被继续执行。并且线程所持有的资源将不会被释放。
等待结束(join)和谦让(yield)
和字面意思一样。
线程组
public class ThreadGroupName implements Runnable { public static void main(String[] args) { //建立一个线程组 ThreadGroup tg = new ThreadGroup("PrintGroup"); //创建线程的时候将线程加入到线程组,使用了Thread的构造函数: //public Thread(ThreadGroup group, Runnable target, String name) Thread t1 = new Thread(tg, new ThreadGroupName(), "T1"); Thread t2 = new Thread(tg, new ThreadGroupName(), "T2"); t1.start(); t2.start(); //线程组中活动线程的总数,但是由于线程是动态的,所以这个只是一个估计值 System.out.println(tg.activeCount()); //列出线程组中的线程 tg.list(); } @Override public void run() { String groupAndName = Thread.currentThread().getThreadGroup().getName() + "-" + Thread.currentThread().getName(); while (true) { System.out.println("I am " + groupAndName); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } } }}
运行结果:
运行结果
线程组还有一个应用就是ThreadGroup.stop()方法,不过其所存在的问题和Thread.stop()一样,因此使用时需要格外谨慎。
守护线程
守护线程是一种特殊的线程,它是系统的守护者,在后台默默地完成一些系统性的服务,比如垃圾回收线程、JIT线程就可以理解为守护线程。与之相对应的是用户线程,用户线程可以认为j是系统的工作线程。如果用户线程全部结束,这也意味这这个程序实际上无事可做了。守护线程要守护的对象已经不存在了,那么整个应用程序就自然应该结束。因此,当一个Java应用内,只有守护线程的时候,Java虚拟机就会自然退出。
简单看下守护线程的使用:
public class DaemonDemo { public static class DaemonT extends Thread{ public void run(){ while(true){ System.out.println("I am alive"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) throws InterruptedException { Thread t=new DaemonT(); //必须在start()之前设置为守护线程 t.setDaemon(true); t.start(); Thread.sleep(2000); }}
注意:守护线程Thread.setDaemon(true)必须要在线程start()之前设置,否则抛出java.lang.IllegalThreadStateException。设置无效,也不影响原来线程作为工作线程继续工作
线程优先级
在java中,使用1到10表示线程优先级(数字越大优先级越高)。一般可以使用Thread类中定义的三个静态标量来表示:
线程优先级
Thread.setPriority()例子
- 线程的基本操作
- 线程的基本操作
- 线程的基本操作
- 线程的基本操作
- Java线程的基本操作
- Qt:线程的基本操作
- 线程同步的基本操作
- java中线程的基本操作!
- 线程的创建、终止、等待基本操作
- 线程的基本操作(后续补充)
- 线程的基本操作(一)
- 线程的基本操作(二)
- 【Linux系统编程】线程的基本操作
- Java 线程的基本状态和操作
- 多线程开发1--线程的基本操作
- day_16_TCP、UDP、线程的基本操作
- Day19—线程的基本操作、线程的同步机制
- Linux中的线程与线程的基本操作
- Nginx详解以及LNMP的搭建
- es6学习随笔
- 加1乘2平方
- Python3_Print输出带颜色字体
- 配置ImageLoader框架
- 线程的基本操作
- 浅析C语言中的数据对齐
- hadoop dfsadmin -report命令详细信息
- 一些容易忽略的小知识
- 移动端web页面知识小结之meta部分(转载)
- JAVA中Static关键字解析
- 导航菜单示例
- 角色
- ServletInputStream available bug?