java线程

Posted wjw0324

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java线程相关的知识,希望对你有一定的参考价值。

一、线程状态与生命周期

 

技术分享图片

 

 

技术分享图片

 

二、阻塞状态

如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种:

  • 等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。

  • 同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)。

  • 其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。

三、线程创建的代码

public class ThreadTwo extends  Thread{

    private String threadName;

    public ThreadTwo(String name){
        this.threadName=name;
    }
    public void run(){
        for (int i=0;i<1000;i++){
            System.out.println("This is "+threadName);
        }
    }
}

 

public class ThreadThree implements Runnable{

    private String threadName;

    ThreadThree(String name) {
        threadName = name;
    }

    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("This is " + threadName);
        }
    }
}
    public static void main(String[] args) throws IOException {
        //runnable接口  抽象内部类的形式
        /**
         * 适用于只是通过线程去掉一下方法,比如在service中处理业务,不想因为异常而影响到当前线程的进行,那么可以 另
         * 起一个线程去做这件事:比如发送消息队列,调用第三方等等。
         */
        new Runnable(){
            @Override
            public void run() {
                for (int i=0;i<1000;i++){
                    System.out.println("This is threadOne");
                }
            }
        }.run();
        //继承thread
        ThreadTwo threadTwo=new ThreadTwo("threadTwo");
        //实现runnable接口
        ThreadThree threadThree=new ThreadThree("threadtThree");
        threadTwo.start();
        threadThree.run();
    }

个人 觉得实现接口的方式比较好,因为java可以多实现,单只能单一继承,如果这个线程类需要有其他接口的功能时候就不能满足了。

四、wait 与sleep的区别

  sleep 和 wait都能是线程进入阻塞状态,让出cpu资源

  sleep方法是属于Thread的,可以设置线程睡眠的时间。wait方法是属于object类的,waitk可以使对象锁释放。

五、interrupt

  interrupt()方法,是将当前的线程进行中断,但是并不能中断进行中run方法中执行的程序,只是改变了该线程的状态,此时为中断状态

  isInterrupted() 是判断当前线程是否为中断状态,如果是为true

  Thread.interrupted() 是线程的一个static方法,是恢复中断之前的状态。

  

public class TestInterrupted implements Runnable{

    public static void main(String[] args){
        Thread thread=new Thread(new TestInterrupted());
        thread.start();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread.interrupt();
        System.out.println("main end");
    }


    @Override
    public void run() {
        while(true){
            if(Thread.currentThread().isInterrupted()){
                //Thread.interrupted();
                System.out.println("Yes, i am interrupted,but i am still  running");
               // return;
            }else{
                System.out.println("not yet interrupted");  //执行想要执行 的程序,一旦线程中断状态,就return是程序中段。
            }

        }
    }
}

输出结果:2秒钟之后,会不断输出 

Yes, i am interrupted,but i am still  running
说明此时线程未中断。
当调用Thread.interrupted() 那么线程就会恢复原来的状态,继续输出
not yet interrupted


那么如果我们需要中断怎么办,可以在方法中加一个return,但是这样就失去了意义。
其实一般我们普遍的做法是加一个开关。这样就可以控制线程中断。

 

public class TestInterruptedTwo implements Runnable{

    private static  boolean  flag=false;
    public static void main(String[] args){
        Thread thread=new Thread(new TestInterruptedTwo());
        thread.start();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread.interrupt();
        flag=true;
        System.out.println("main end");
    }


    @Override
    public void run() {
        while(!flag){
            if(Thread.currentThread().isInterrupted()){
                //Thread.interrupted();
                System.out.println("Yes, i am interrupted,but i am still  running");
            }else{
                System.out.println("not yet interrupted");
            }

        }
    }
}

  当一个线程正在阻塞状态使,调用interrupt方法,会抛出异常。一旦该线程进入到 wait()/sleep()/join()后,就会立刻抛出InterruptedException 。

public class TestInterruptedTwo implements Runnable{

    private static  boolean  flag=false;
    public static void main(String[] args){
        Thread thread=new Thread(new TestInterruptedTwo());
        thread.start();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread.interrupt();
        flag=true;
        System.out.println("main end");
    }


    @Override
    public void run() {
        while(!flag){
                System.out.println("i am sleepping");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
输出结果

i am sleepping
i am sleepping
main end
java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at wjw.thread.TestInterruptedTwo.run(TestInterruptedTwo.java:31)
    at java.lang.Thread.run(Thread.java:748)

六.wait,notify(),notifyAll()的使用。

  首先这三个方法只能在同步块中使用

  wait()方法是Object类里的方法;当一个线程执行到wait()方法时,它就进入到一个和该对象相关的等待池中,同时失去(释放)了对象的机锁(暂时失去机锁,wait(long timeout)超时时间到后还需要返还对象锁);其他线程可以访问;
  wait()使用notify或者notifyAlll或者指定睡眠时间来唤醒当前等待池中的线程。,这里的 唤醒不是中断的意思,而是是这个线程进行进入就绪状态,可以继续执行。

  

public class ThreadTestTwo {
    
    public static void main(String[] args){
        new Thread(new Thread1()).start();
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(new Thread2()).start();
    }

    static class Thread1 implements Runnable{

        @Override
        public void run() {
            synchronized (ThreadTestTwo.class){

                    System.out.println("enter thread1");
                    System.out.println("thread1 is waitting");
                try {
                    ThreadTestTwo.class.wait();   //使线程1进入等待状态,同时释放该对象锁,这样其他的线程才能在该对象的同步快中进行执行代码
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                    System.out.println("thread1 is going on ....");
                    System.out.println("thread1 is over!!!");
                

            }
        }
    }

    static class Thread2 implements  Runnable{

        @Override
        public void run() {
            synchronized(ThreadTestTwo.class){
                    System.out.println("enter thread2");
                    System.out.println("thread2 is sleepping");
                    ThreadTestTwo.class.notifyAll();
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("thread2 is going");
                    System.out.println("thread2 is over");
            }

        }
    }
    
}
输出结果
enter thread1
thread1 is waitting
enter thread2
thread2 is sleepping
thread2 is going
thread2 is over
thread1 is going on ....
thread1 is over!!!

如果没有wait()方法, 那么对象锁将不会被释放,只有等待当前线程执行完了,持有该对象同步块的其他线程才能继续执行。

notify 与notifyAll()的区别

线程调用了wait()方法后将会在对象池中等待。

如果所有线程都在此对象上等待,notify方法只能随机唤醒一个的线程,

notifyAll, 唤醒在此对象监视器上等待的所有线程。

大家自己可以去试一试,同事创建多个线程,都调用了wait方法,然后只调用notify方法,看看是否随机唤醒其中一个线程。或者这个优先级有没有关系?

七、线程的优先级

  前面讲到sleep()方法,当睡眠时间到了,并不会立即执行该线程,除非它的线程优先级很前面

  设置优先级的方法。10,5,1

Thread thread1=new Thread(new ThreadTestThree());
thread1.setPriority(Thread.MAX_PRIORITY);
八、join()
join的功能,相当于抢锁(方法锁),抢了之后,调用wait()方法释放锁,是当前的线程进入等待状态;join(5000),抢了锁之后,释放锁,等待5秒钟。这5秒时间,给其他的线程让出资源。等待时间到了,会跳出阻塞,详细见join源码。
至于是谁调用了join不要紧,和调用方是没有关系的,关键是在那个线程里调用。
public class TestJoin  {

public static void main(String[] args){

Thread parent=new Thread(new Parent());
parent.start();
}


static class Child implements Runnable{
long begin=System.currentTimeMillis();
@Override
public void run() {

while(true){
System.out.println("child is enter");
System.out.println("child is going");
System.out.println("child is sleeping");
System.out.println(System.currentTimeMillis());
try {
Thread.sleep(8000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("child is waking");
System.out.println("child is over");
System.out.println(System.currentTimeMillis());
long end =System.currentTimeMillis();
if(end-begin>1000){
break;
}
}

}
}

static class ClassA{

}
static class Parent implements Runnable{

@Override
public void run() {


System.out.println("parent is enter");
System.out.println("child is join");
Thread child=new Thread(new Child());
child.start();
try {
child.join(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("parent is going");
System.out.println("parent is over");
System.out.println(System.currentTimeMillis());

}
}

}


执行结果
parent is enter
child is join
child is enter
child is going
child is sleeping
1546095766103
parent is going
parent is over
1546095771104
child is waking
child is over
1546095774105

附上 join的源码

public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

wait()一段时间后,如果等待时间超过millis,则可以break跳出阻塞。













































































以上是关于java线程的主要内容,如果未能解决你的问题,请参考以下文章

Java工程师面试题,二级java刷题软件

java线程

Java——线程池

Java线程池详解

Java线程池详解

Java 线程池详解