JAVA多线程

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(),但也是接口,并且有返回值、能够抛出异常

线程的状态

  1. 创建状态:创建线程后占用空间和其他资源,但处于不可运行状态
  2. 就绪状态:调用start()方法后进入就绪状态,线程将进入线程队列进行排队,等待cpu服务
  3. 运行状态:cpu已经开始运行这个线程,并且自动调用run() 或者 call()方法
  4. 堵塞状态:人为挂起或者执行耗时的输入输出时进入阻塞状态,CPU暂时中止执行,当堵塞结束时,线程转入就绪状态
  5. 死亡状态:当遇到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() );
        }
    }
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值