Thread 类
是Runnable接口的子类,通过继承它来实现多线程,主方法为必须覆写run()方法
class myThread extends Thread{
private int ticket;
public void setTicket(int ticket){
this.ticket=ticket;
}
public void run(){ //必须覆写run方法
while(ticket>0){
System.out.println("Remaining votes:"+ticket--);
}
}
}
public class Main{
myThread t=new myThread();
t.setTicket(10);
t.start(); //启动线程
myThread t1=new myThread();
myThread t2=new myThread();
t1.start();
t2.start(); //这两个线程各自用各自的资源,但是同时运行
}
Runnable 接口
通过实现Runnable接口,也必须覆写run方法
class myThread implements Runnable{
private ticket;
public void setTicket(int ticket){
this.ticket=ticket;
}
public void run(){
while(ticket>0){
System.out.println("Remaining votes:"+ticket--);
}
}
}
public class Main{
myThread t=new myThread();
t.setTicket(10);
t.start(); //启动线程
}
启动线程
Thread.start() 方法
如果直接继承的Thread那么实例可以直接调用start()
如果实现的接口,那么实例需要向下转型(多态):myIntface t=new myIntface();
Thread t1=new Thread(t); //向下转型,Thread(Runnable target)
myInterface t=new myInterface(); //由于Runnable接口中没有start()
Thread m=new Thread(t); //利用Thread构造方法,用定义的接口使用start()方法
Thread m2=new Thread(t); //传过去同一个Runnable实例,所以资源共享
//这里所谓的资源共享,实际上就是两个线程用的同一个实例
myThread T=new myThread(); //直接继承Thread类的实例,可以直接调用start()
myThread T1=new myThread();
T.start();
T1.start(); //这里是两个互相独立的实例,所以就没有所谓的资源共享
Thread与Runnable的区别
在上面的代码块注释里面解释了,本质上的区别就是接口与类的区别
使用的区别:
因为Thread(Runnable target),所以用Runnable实现时,一个实例可以多个线程使用
因为Thread是直接继承的,本身就自带start()方法,虽说也可以实现资源共享,但麻烦一点
Callable接口
由于Runnable 接口没有返回值,所以就提供一个新接口:Callable
实现Callable 接口必须覆写 call() 方法
/*
每个线程传递两个值:start,end 求出start到end之间的素数,返回素数个数
*/
class myThread implements Callable<Integer>{ //Integer 返回值类型
private int start;
private int end;
public myThread(int start,int end){
this.start=start;
this.end=end;
}
public Integer Callable() throws Exception{
for(int i=start;i<=end;i++){
boolean flag=true;
for(int j=2;j<=Math.sqrt(end);j++){
if(i%j==0){
flag=true;
break;
}
}
if(flag){
System.out.println("No."+(++sum) +"="+i);
}
}
}
return sum;
}
以上是Callable 接口的实现,下面写如何调用线程
public class Zyy{
public static void main() throws Exception{
myThread m1=new myThread(10,100);
myThread m2=new myThread(100,200); //实例化两个多线程对象
FutureTask<Integer> task1=new FutureTask<Integer>(m1);
FutureTask<Integer> task2=new FutureTask<Integer>(m2);
//FutureTask 是Runnable接口的子类,可以接收Callable 实例
//由于Thread 只能接受Runnable 接口类型,所以需要用到FutureTask
//FutureTask.get() 可以获取Callable的返回值
new Thread(task1).start();
new Thread(task2).start(); //利用FutureTask,再Thread.start() 启动线程
System.out.println("The result of first one is:" + task1.get());
System.out.println("The result of second one is:" + task2.get());
//输出两个线程的返回结果
}
}
小结
- Thread 继承后可以直接使用start() 方法,但是有单继承的局限性
- Runnable 实现后需要用到Thread.start() 才能启动线程,但是实现接口更加灵活
- Callable 实现后需要用到FutureTask,再用到Thread.start(),但也是接口,并且有返回值、能够抛出异常
线程的状态
- 创建状态:创建线程后占用空间和其他资源,但处于不可运行状态
- 就绪状态:调用start()方法后进入就绪状态,线程将进入线程队列进行排队,等待cpu服务
- 运行状态:cpu已经开始运行这个线程,并且自动调用run() 或者 call()方法
- 堵塞状态:人为挂起或者执行耗时的输入输出时进入阻塞状态,CPU暂时中止执行,当堵塞结束时,线程转入就绪状态
- 死亡状态:当遇到stop()方法或者run()方法执行完毕后,处于死亡状态,不具有继续运行的能力
线程操作的方法
方法名 | 类型 | 描述 |
---|---|---|
public Thread(Runnable target,String name) | 构造 | 接受Runnable接口,创建线程名称 |
public static Thread cuurentThread() | 普通 | 返回当前正在执行的线程 |
public final String getName() | 普通 | 返回线程名 |
public final int getPriority() | 普通 | 返回线程优先级 |
public boolean isInterrupte() | 普通 | 返回线程是否被中断(中断 true) |
public final boolean isAlive() | 普通 | 返回线程是否在活动(活动 true) |
public final void join() thorws InterrputedException | 普通 | 等待线程执行 |
public final void join(long s) throws InterrputedException | 普通 | s毫秒后线程死亡 |
public void run() | 普通 | 执行线程 |
public final void setName(String name) | 普通 | 设置线程名称 |
public final void setPriority(int x) | 普通 | 设置线程的优先级 |
public static void sleep(int s) throws InterrputedException | 普通 | 使目前正在执行的线程休眠s毫秒 |
public void start() | 普通 | 开始执行线程 |
public String toString() | 普通 | 返回代表线程的字符串 |
public static void yield() | 普通 | 使目前正在执行的线程暂停,允许其他执行 |
public final void setDaemon(boolean on) | 普通 | 将一个线程设置为后台运行 |
取得和设置线程名称
Thread类中,getName()取得线程名,setName()设置线程名
如果不设置线程名,系统会自动设置 Thread-X 名字
强制执行线程(需要异常处理)
线程调用join() 方法后,其他线程要等待这个线程执行完毕,才能执行
最好在其他线程执行之前 调用join() 方法,否则可能在调用此方法前,其他不该运行的线程已经开始运行了一段时间
public class Main {
public static void main(String[] args) throws Exception {
myThread2 m1=new myThread2();
myThread2 m2=new myThread2();
m1.setName("先执行");
m2.setName("后执行"); //设置线程内的属性值
Thread t=new Thread(m1,"ZYY");
Thread t2=new Thread(m2,"HH"); //实例化 Thread类
t.start(); //启动 t线程
try {
t.join(); //t线程执行完毕,其他线程才能执行
} catch (Exception e){
System.out.println("ERROR!!!!!");
};
t2.start(); //要等t线程执行完毕,这个线程才会执行
}
}
线程休眠(需要异常处理)
class myThread2 implements Runnable{
private String name;
private int age;
public void setName(String name){
this.name=name;
}
public void setAge(int age){
this.age=age;
}
public void run(){
while (age <= 120) {
try{
Thread.sleep(1000); //休眠1000毫秒
} catch (Exception e){
e.printStackTrace();
return;
}
System.out.println(name + " Age:" + age++);
}
}
}
中断线程
- 使用 interrupt() + InterruptedException来中断线程
class myThread2 implements Runnable{
private int age;
public int getAge(){
return this.age;
}
public void setAge(int age){
this.age=age;
}
public void run(){
while (age <= 120) {
try {
Thread.sleep(100);
} catch (Exception e) { //执行interrupted 方法后这里会捕获到异常
System.out.println("Stop!!!!");
return; //结束方法
}
System.out.println(name + " Age:" + age++);
}
}
}
public class Main {
public static void main(String[] args) throws Exception {
myThread2 m1=new myThread2();
m1.setName("先执行");
Thread t1=new Thread(m1);
t1.start();
while (t1.isAlive()){
if(m1.getAge()>20) //一旦超过20就interrupt()改变为中断状态
t1.interrupt(); //此时执行sleep会抛出 InterruptedException 异常
}
}
}
-
使用 interrupted() 与 isInterupted()
class myThread1 extends Thread{ private int ticket; public int getTicket(){ return ticket; } public void setTicket(int ticket){ this.ticket = ticket; } public void run(){ while(ticket>0&&!this.isInterrupted()){ //以isInterrupted方法作为控制变量 try { sleep(200); } catch (Exception e){ e.printStackTrace(); } System.out.println("Remaining votes:" + ticket-- ); } } } public class Main { public static void main(String[] args) throws Exception { myThread1 m=new myThread1(); m.setTicket(50); m.start(); while (m.isAlive()){ if(m.getTicket()<20){ m.interrupt(); //如果票数小于20则设置为中断状态 } } }
后台线程
守护线程,为其他线程提供服务,当所有前台线程都死亡,守护线程也会自动死亡
要在线程启动前设置为后台线程
t1.setDaemon(true);
线程的优先级
setPriority() 方法设置优先级,共有三种
public static final int MIN_PRIORITY 最低优先级 1 public static final int NORM_PRIORITY 中等优先级 **5 ** public static final int MAX_PRIORITY 最高优先级 10 高优先级的线程大部分先执行,不是完全先执行
class myThread1 extends Thread{ private int ticket; public int getTicket(){ return ticket; } public void setTicket(int ticket){ this.ticket = ticket; } public void run(){ while(ticket>0){ try { sleep(100); } catch (Exception e){ e.printStackTrace(); } System.out.println("Remaining votes:" + ticket-- + " " + this.getName() ); System.out.println(this.getName() + " "+this.getPriority()); } } } public class Main { public static void main(String[] args) throws Exception { myThread1 m=new myThread1(); myThread1 m1=new myThread1(); m.setName("FIRST"); m1.setName("SECOND"); //设置线程名 m1.setTicket(50); m.setTicket(50); m.setPriority(Thread.MAX_PRIORITY); m1.setPriority(Thread.MIN_PRIORITY); //在启动线程前设置优先级 m.start(); m1.start(); //启动线程 } }
运行了似乎没有太大差别
线程的礼让
class myThread1 extends Thread{
private int ticket;
public void setTicket(int ticket){
this.ticket = ticket;
}
public void run(){
while(ticket>0){
try {
sleep(100);
} catch (Exception e){
e.printStackTrace();
}
if(ticket<=10&&"FIRST".equals(this.getName())){
Thread.yield(); //线程礼让
}
System.out.println("Remaining votes:" + ticket-- + " " + this.getName() );
}
}
}