美文网首页
初识Java多线程

初识Java多线程

作者: 人生逆旅我亦行人 | 来源:发表于2020-04-22 10:04 被阅读0次

第一章 Java多线程技能

1)线程的启动;
2)如何使线程暂停;
3)线程的优先级;
4)线程安全相关的问题

1.1 进程和多线程的概念及多线程的优点

进程:受操作系统管理的基本运行单元。

线程:进程中独立运行的子任务。

多线程的优点:
在图1-1-1中,任务1与任务2是两个完全独立,互不相关的任务,任务1在等待远程服务器返回数据,这时CPU一直“空运行”,必须要等到任务1执行完毕后才执行任务2。以上概括了单任务的特点:排队执行,也就是同步。这就是单任务环境的缺点,CPU利用率大幅降低。
在图1-1-2可以发现,CPU完全可以再任务1与任务2之间来回切换,使任务2不必等待任务1执行完毕再进行,系统的运行效率大大提升。

image

1.2 使用多线程

实现多线程的的方式有两种,一种是继承Thread类,另一种是实现Runnable接口。

1.2.1 继承Thread类

public class Thread implements Runnable{}

使用继承Thread类的方式来创建多线程时,最大的局限性就是不支持多继承(Java语言的特点就是单根继承)。下面使用第一种方式,继承Thread类。

public class MyThread extends Thread {
    @Override
    public void run() {
        super.run();
        System.out.println("MyThread");
    }
}
public class Run{
    public static void main(String[] args) {
        MyThread myThread =new MyThread();
        myThread.start();
        System.out.println("运行结束");
    }
}
运行结束
MyThread

从执行结果来看,MyThread类中run方法执行的时间较晚,这也说明在使用多线程技术时,代码的运行结果与代码的执行顺序或调用顺序是无关的。线程是一个子任务,CPU以不确定的方式,或者说是以随机的时间来调用线程中的run方法,所以就会出现如上结果。 如果多次调用start(),则会出现 Exception in thread "main" java.lang.IllegalThreadStateException

上面介绍了线程调用的随机性,下面我们再演示线程的随机性,如下。

public class MyThread extends Thread{
    @Override
    public void run() {
        try {
            for (int i = 0; i < 5; i++) {
                int time =(int) (Math.random() * 1000);
                Thread.sleep(time);
                System.out.println("run=" + Thread.currentThread().getName());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class Run{
    public static void main(String[] args) {
        try {
            MyThread myThread =new MyThread();
            myThread.setName("MyThread");
            myThread.start();
            for (int i = 0; i < 5; i++) {
                int time =(int) (Math.random() * 1000);
                Thread.sleep(time);
                System.out.println("main=" + Thread.currentThread().getName());
            }
        } catch (InterruptedException e) {
            e.fillInStackTrace();
        }
    }
}

run=MyThread
main=main
main=main
run=MyThread
run=MyThread
main=main
run=MyThread
run=MyThread
main=main
main=main

继承Thread,重写run方法,调用start方法执行线程的流程:调用Thread类中的start方法通知线程规划器此线程已经准备就绪,等待调用线程对象的run方法。这个过程其实就是让系统安排一个时间来调用Thread中的run方法,使线程得到运行,线程为异步执行;如果直接调用Thread.run(),那么此线程对象并不交给“线程规划器”来处理,而是由main主线程来调用run(),也就是同步执行。

1.2.2 实现Runnable接口

如果预创建的线程类已经有一个父类了,这时候就不能再继承Thread了,因为Java不支持多继承,所以就需要实现Runnbale接口来应对这种情况。 如何使用Runnable接口呢,那么就要看一下Thread的构造函数了。

public Thread(){}
public Thread(Runnable target){}
public Thread(ThreadGroup group, Runnable target){}
public Thread(String name){}
public Thread(ThreadGroup group, String name){}
public Thread(Runnable target, String name){}
public Thread(ThreadGroup group, Runnable target, String name){}
public Thread(ThreadGroup group, Runnable target, String name, long stackSize){}

在Thread类的8个构造函数中,有两个个构造函数

Thread(Runnable target)
Thread(Runnable target, String name)
public class MyRunnable implements Runnable{
    @Override
    public void run() {
        System.out.println("running");
    }
}
public class RunMyRunnable{
    public static void main(String[] args) {
        Thread thread  =new Thread(new MyRunnable());
        System.out.println(thread.getName());
        thread.start();
        Thread thread2  =new Thread(new MyRunnable(),"customize name");
        System.out.println(thread2.getName());
        thread2.start();
        System.out.println("运行结束");
    }
}

Thread-0
customize name
运行结束
running
running

1.2.3 实例变量与线程安全

自定义线程类中的实例变量针对其他线程有共享不共享之分,这在多线程之间进行交互时是很重要的一个技术点。

1.2.3.1 不共享数据的情况

public class MyThread extends Thread{
    private int count =5;
    public MyThread(String name) {
        this.setName(name);
    }
    @Override
    public void run() {
        super.run();
        while (count >0) {
            count--;
            System.out.println("由" +this.currentThread().getName() +"计算,count=" +count);
        }
    }
}
public class Run{
    public static void main(String[] args) {
        MyThread myThreadA =new MyThread("myThreadA");
        MyThread myThreadB =new MyThread("myThreadB");
        MyThread myThreadC =new MyThread("myThreadC");
        myThreadA.start();
        myThreadB.start();
        myThreadC.start();
    }
}
由myThreadA计算,count=4
由myThreadC计算,count=4
由myThreadC计算,count=3
由myThreadC计算,count=2
由myThreadC计算,count=1
由myThreadC计算,count=0
由myThreadA计算,count=3
由myThreadA计算,count=2
由myThreadA计算,count=1
由myThreadA计算,count=0
由myThreadB计算,count=4
由myThreadB计算,count=3
由myThreadB计算,count=2
由myThreadB计算,count=1
由myThreadB计算,count=0

1.2.3.2 共享数据的情况

共享数据是指多个线程同时访问同一个变量。

public class MyThread extends Thread{
    private int count =5;
    @Override
    public void run() {
        super.run();
        count--;
        System.out.println("由" +this.currentThread().getName() +"计算,count=" +count);
    }
}
public class Run{
    public static void main(String[] args) {
        MyThread myThreadA =new MyThread();
        Thread a =new Thread(myThreadA,"A");
        Thread b =new Thread(myThreadA,"B");
        Thread c =new Thread(myThreadA,"C");
        Thread d =new Thread(myThreadA,"D");
        Thread e =new Thread(myThreadA,"E");
        a.start();
        b.start();
        c.start();
        d.start();
        e.start();
    }
}
由C计算,count=3
由B计算,count=3
由A计算,count=2
由E计算,count=1
由D计算,count=0

线程C和B打印出的count值都是3,说明A和B同时获取到count并进行--的操作,产生了非线程安全问题。count--的操作分成三步:
1)取得原有count值;
2)计算count-1;
3)对count赋值。
如果多个线程同时访问,一定会出现非线程安全问题。

那么如何解决上面的线程安全问题呢?这时就需要使多个线程之间进行同步。更改MyThread类代码如下:

public class MyThread extends Thread{
    private int count =5;
    @Override
    synchronized public void run() {
        super.run();
        count--;
        System.out.println("由" +this.currentThread().getName() +"计算,count=" +count);
    }
}
由A计算,count=4
由E计算,count=3
由B计算,count=2
由D计算,count=1
由C计算,count=0

运行之后,执行结果与预期一致。通过在run方法前加入synchronized,使多个线程在执行run方法时,以排队的方式进行处理。当一个线程调用run前,先判断run方法有没有被上锁,如果上锁,说明有其他线程正在调用run方法,必须等其他线程对run方法调用结束之后才可以执行。这样也就实现了排队调用run方法的目的。synchronized可以在任意对象及方法上加锁,而加锁的这段代码成为互斥区临界区

当一个线程想要执行同步方法里面的代码时,线程首先尝试去拿这把锁,如果能拿到这把锁,那么这个线程就可以执行synchronized里面的代码。如果不能获取这把锁,那么这个线程就会不断地尝试拿这把锁,直到拿到为止。

非线程安全主要是指多个线程对同一对象中的同一实例变量进行操作时,会出现值被更改,值不同步的情况,进而影响程序的执行流程。

下面来实现一个非线程安全导致的后果。

public class LoginServlet{
    private static StringuserNameRef;
    private static StringpasswordRef;
    public static void login(String userName, String password) {
        userNameRef = userName;
        try {
            if (userName.equals("a")) {
                Thread.sleep(5000);
            }
            passwordRef = password;
            System.out.println("当前的用户名:" +userNameRef +" 密码:" +passwordRef);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class ALogin extends Thread{
    @Override
    public void run() {
        LoginServlet.login("a", "aa");
    }
}
public class BLogin extends Thread{
    @Override
    public void run() {
        LoginServlet.login("b", "bb");
    }
}
public class DoLogin{
    public static void main(String[] args) {
        ALogin a =new ALogin();
        a.start();
        BLogin b =new BLogin();
        b.start();
    }
}
当前的用户名:b 密码:bb
当前的用户名:b 密码:aa

解决这个非线程安全的方法也是使用synchronized,更改代码如下:

public class LoginServlet{
    private static StringuserNameRef;
    private static StringpasswordRef;
    synchronized public static void login(String userName, String password) {
        userNameRef = userName;
        try {
            if (userName.equals("a")) {
                Thread.sleep(5000);
            }
            passwordRef = password;
            System.out.println("当前的用户名:" +userNameRef +" 密码:" +passwordRef);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
当前的用户名:a 密码:aa
当前的用户名:b 密码:bb

1.3 currentThread()

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

1.4 isAlive()

判断当前线程是否处于活动状态。活动状态就是线程已经启动且尚未终止,线程处于正在运行或准备开始运行的状态,就认为线程是“存活的”。

1.5 sleep()

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

1.6 getId()

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

1.7 停止线程

停止一个线程意味着在线程处理完任务之前停掉正在做的操作。虽然看起来很简单,但是必须做好防范措施,以便达到预期效果。
在Java中有三种方法可以终止正在运行的线程:
1)使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。
2)使用stop方法(已经被作废)强行终止线程。但是不推荐使用此方法,因为stopsuspedresume一样都是作废过期的方法。
3)使用interrupt方法中断线程。

1.7.1 停止不了的线程

interrupt方法仅是在当前线程中打了一个停止的标记,并不是真的停止线程。

public class MyThread extends Thread{
    @Override
    public void run() {
        super.run();
        for (int i =0; i <500000; i++) {
            System.out.println("i=" + i);
        }
    }
}
public class Run{
    public static void main(String[] args) {
        MyThread thread =new MyThread();
        thread.start();
        thread.interrupt();
    }
}

从运行结果来看,调用interrupt方法并没有停止线程。

1.7.2 判断线程是否是停止状态

1)this.interrupted():测试当前线程是否已经中断,执行后具有将状态标志清除为false的功能。
2)this.isInterrupted():测试当前线程是否已经中断,不清除状态标志。

1.7.3 能停止的线程-异常法

public class MyThread extends Thread{
    @Override
    public void run() {
        super.run();
        for (int i =0; i <500000; i++) {
            if (this.isInterrupted()) {
                System.out.println("停止状态 退出");
                break;
            }
            System.out.println("i=" + i);
        }
    }
}
public class Run{
    public static void main(String[] args) {
        try {
            MyThread thread =new MyThread();
            thread.start();
            Thread.sleep(2000);
            thread.interrupt();
        } catch (Exception e) {
            System.out.println("main catch");
            e.printStackTrace();
        }
        System.out.println("end");
    }
}
i=408980
i=408981
i=408982
i=408983
i=408984
end
停止状态 退出

上面示例代码虽然停止了线程但如果for下面还有语句,还是会运行的,该如何解决语句继续运行的问题呢 ?

public class MyThread extends Thread{
    @Override
    public void run() {
        super.run();
        try {
            for (int i =0; i <500000; i++) {
                if (this.isInterrupted()) {
                    System.out.println("停止状态 退出");
                    throw new InterruptedException();
                }
                System.out.println("i=" + i);
            }
            System.out.println("for之后运行,线程并未停止");
        } catch (Exception e) {
            System.out.println("MyThread catch");
            e.printStackTrace();
        }
    }
}
public class Run{
    public static void main(String[] args) {
        try {
            MyThread thread =new MyThread();
            thread.start();
            Thread.sleep(2000);
            thread.interrupt();
        } catch (Exception e) {
            System.out.println("main catch");
            e.printStackTrace();
        }
        System.out.println("end");
    }
}
i=410919
i=410920
i=410921
end
停止状态 退出
MyThread catch
java.lang.InterruptedException

1.7.4 在沉睡中停止

如果线程在sleep状态下停止线程,会是什么效果呢?

public class MyThread extends Thread{
    @Override
    public void run() {
        super.run();
        try {
            System.out.println("run begin");
            Thread.sleep(20000);
            System.out.println("run end");
        } catch (InterruptedException e) {
            System.out.println("在沉睡中被停止!进入catch!" +this.isInterrupted());
            e.printStackTrace();
        }
    }
}
public class Run{
    public static void main(String[] args) {
        try {
            MyThread thread =new MyThread();
            thread.start();
            Thread.sleep(200);
            thread.interrupt();
        } catch (Exception e) {
            System.out.println("main catch");
            e.printStackTrace();
        }
        System.out.println("end");
    }
}
run begin
end
在沉睡中被停止!进入catch!false
java.lang.InterruptedException: sleep interrupted

sleep状态下,停止某一线程,会进入catch语句,并清除停止状态值,使之变成false

1.7.5 能停止的线程-暴力停止

使用stop方法停止线程则是非常暴力的。

public class MyThread extends Thread{
    private int i =0;
    @Override
    public void run() {
        try {
            while (true) {
                i++;
                System.out.println("i=" +i);
                Thread.sleep(1000);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
public class Run{
    public static void main(String[] args) {
        try {
            MyThread thread =new MyThread();
            thread.start();
            Thread.sleep(8000);
            thread.stop();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
i=1
i=2
i=3
i=4
i=5
i=6
i=7
i=8
i=9

1.7.6 stop()与java.lang.ThreadDeath异常

调用stop()时会抛出java.lang.ThreadDeath异常。该方法已经被作废,因为如果强制让线程停止则有可能使一些清理性的工作得不到完成。另外一个情况就是对锁定的对象进行了解锁,导致数据得不到同步的处理,出现数据不一致的问题。

1.7.7 释放锁的不良后果

使用stop()释放锁将会给数据造成不一致性的结果。如果出现这样的情况,程序处理的数据就有可能遭到破坏,最终导致程序执行流程错误,一定要特别注意。

public class SynchronizedObject{
    private String userName ="a";
    private String password ="a";
    public String get UserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public void printString(String userName, String password) {
        try {
            this.userName = userName;
            Thread.sleep(100000);
            this.password = password;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class MyThread extends Thread{
    private SynchronizedObject syncObject;
    public MyThread(SynchronizedObject syncObject) {
        this.syncObject = syncObject;
    }
    @Override
    public void run() {
        syncObject.printString("b", "bbb");
    }
}
public class Run{
    public static void main(String[] args) {
        try {
            SynchronizedObject syncObject =new SynchronizedObject();
            MyThread thread =new MyThread(syncObject);
            thread.start();
            Thread.sleep(8000);
            thread.stop();
            System.out.println(syncObject.getUserName() +"  " +syncObject.getPassword());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
b a

1.7.8 使用return停止线程

interruptreturn结合使用也能实现停止线程的效果。

public class MyThread extends Thread{
    @Override
    public void run() {
        while (true) {
            if (this.isInterrupted()) {
                System.out.println("stop");
                return;
            }
            System.out.println("current time=" + System.currentTimeMillis());
        }
    }
}
public class Run{
    public static void main(String[] args) {
        try {
            MyThread thread =new MyThread();
            thread.start();
            Thread.sleep(8000);
            thread.interrupt();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
current time=1587436071260
current time=1587436071260
stop

不过还是建议使用抛异常的方法来实现线程的停止,因为在catch块中还可以讲一场向上抛,是线程停止的时间得以传播。

1.8 暂停线程

暂停线程意味着此线程还可以恢复运行,在Java多线程中,可以使用suspend()暂停线程,使用resume()恢复线程的执行。

1.8.1 suispend与resume方法的使用

public class MyThread extends Thread{
    private long i =0;
    public long getI() {
        return i;   
    }
    public void setI(long i) {
        this.i = i;
    }
    @Override
    public void run() {
        while (true) {
            i++;
        }
    }
}
public class Run{
    public static void main(String[] args) {
        try {
            MyThread thread =new MyThread();
            thread.start();
            Thread.sleep(5000);
            // 暂停线程
            thread.suspend();
            System.out.println("A=" + System.currentTimeMillis() +" i=" + thread.getI());
            Thread.sleep(5000);
            System.out.println("A=" + System.currentTimeMillis() +" i=" + thread.getI());
            // 恢复
            thread.resume();
            Thread.sleep(5000);
            // 继续暂停
            thread.suspend();
            System.out.println("B=" + System.currentTimeMillis() +" i=" + thread.getI());
            Thread.sleep(5000);
            System.out.println("B=" + System.currentTimeMillis() +" i=" + thread.getI());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

A=1587436765560 i=2885201074
A=1587436770560 i=2885201074
B=1587436775560 i=5820785533
B=1587436780560 i=5820785533

1.8.2 suspend与resume方法的缺点-独占

在使用suspendresume方法时,如果使用不当,极易造成公共的同步对象的独占,是其他线程无法访问公共同步对象。

public class SynchronizedObject{
    synchronized public void printString() {
        System.out.println("begin");
        if (Thread.currentThread().getName().equals("a")) {
            System.out.println("a线程一直suspend···");
            Thread.currentThread().suspend();
        }
        System.out.println("end");
    }
}
public class Run{
    public static void main(String[] args) {
        try {
            final SynchronizedObject syncObject =new SynchronizedObject();
            Thread thread =new Thread(new Runnable(){
                @Override
                public void run() {
                    syncObject.printString();
                }
            });
            thread.setName("a");
            thread.start();
            Thread.sleep(1000);
            Thread thread2 =new Thread(new Runnable(){
                @Override
                public void run() {
                    System.out.println("thread2 begin");
                    syncObject.printString();
                }
            });
            thread2.start();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
begin
a线程一直suspend···
thread2 begin

还有另外一种独占锁的情况也要格外注意,稍有不慎就会进坑。

public class MyThread extends Thread{
    private long i =0;
    public long getI() {
        return i;
    }
    public void setI(long i) {
        this.i = i;
    }
    @Override
    public void run() {
        while (true) {
            i++;
            System.out.println(i);
        }
    }
}
public class Run{
    public static void main(String[] args) {
        try {
            MyThread myThread =new MyThread();
            myThread.start();
            Thread.sleep(1000);
            myThread.suspend();
            System.out.println("main end");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

程序不会再打印“main end”,因为当程序运行到println()方法停止时,同步锁未释放。println()源码如下:

public void println(String x) {
    synchronized (this) {
        print(x);
        newLine();
    }
}

1.8.3 suspend与resume方法的缺点-不同步

在使用suspendresume方法是容易出现因线程暂停而导致数据不同步的情况。

public class MyObject{
    private String userName ="1";
    private String password ="11";
    public void setValue(String userName, String password) {
        this.userName = userName;
        if ("a".equals(Thread.currentThread().getName())) {
            System.out.println("线程a暂停");
            Thread.currentThread().suspend();
        }
        this.password = password;
    }

    public void print() {
        System.out.println(userName +"  " +password);
    }
}
public class Run{
    public static void main(String[] args) throws InterruptedException{
        final MyObject myObject =new MyObject();
        Thread thread =new Thread(new Runnable(){
            @Override
            public void run() {
                myObject.setValue("lala", "lalala");
            }
        });
        thread.setName("a");
        thread.start();
        Thread.sleep(1000);
        new Thread(new Runnable(){
            @Override
            public void run() {
                myObject.print();
            }
        }).start();
    }
}
线程a暂停
lala  11

1.9 yield方法

yield方法的作用是放弃当前的CPU资源,将它让给其他任务去占用CPU执行时间。单放弃的时间不确定,有可能刚刚放弃,马上又获得CPU时间片。

public class MyThread extends Thread{
    @Override
    public void run() {
        long beginTime = System.currentTimeMillis();
        int count =0;
        for (int i =0; i <50000000; i++) {
            // Thread.yield();
            count = count + i +1;
        }
        long endTime = System.currentTimeMillis();
        System.out.println("用时:" +(endTime - beginTime) +"毫秒!");
    }
}
public class Run{
    public static void main(String[] args)  {
        MyThread myThread =new MyThread();
        myThread.start();
    }
}
用时:19毫秒!

取消Thread.yield();注释,再次运行结果如下所示:

用时:11723毫秒!

1.10 线程的优先级

操作系统中,线程和一划分优先级,优先级较高的线程得到的CPU资源较多,也就是CPU有限制性优先级较高的线程对象中的任务。设置线程优先级有助于帮线程规划器确定下一次选择哪一个线程来优先执行。设置线程优先级使用setPriority(),源码如下:

public final void setPriority(int newPriority) {
    ThreadGroup g;
    checkAccess();
    if (newPriority >MAX_PRIORITY || newPriority
        throw new IllegalArgumentException();
    }
    if((g = getThreadGroup()) !=null) {
        if (newPriority > g.getMaxPriority()) {
            newPriority = g.getMaxPriority();
        }
        setPriority0(priority = newPriority);
    }
}

在Java中,线程的优先级分为1至10,这十个等级,如果小于或大于10,则抛出异常 throw new IllegalArgumentException()

JDK中使用三个常量来预定义优先级的值,代码如下:

/**
* The minimum priority that a thread can have.
*/
public final static int MIN_PRIORITY =1;
/**
* The default priority that is assigned to a thread.
*/
public final static int NORM_PRIORITY =5;
/**
* The maximum priority that a thread can have.
*/
public final static int MAX_PRIORITY =10;

1.10.1 线程优先级的继承特性

在Java中,线程的优先级具有继承性,比如A线程启动B线程,则B线程的优先级与A是一样的。


public class MyThread2 extends Thread{
    @Override
    public void run() {
        System.out.println("myThread2 run priority="+this.getPriority());
    }
}
public class MyThread1 extends Thread{
    @Override
    public void run() {
        System.out.println("myThread1 run priority="+this.getPriority());
        MyThread2 thread2 =new MyThread2();
        thread2.start();
    }
}
public class Run{
    public static void main(String[] args)  {
        System.out.println("main thread begin priority="+Thread.currentThread().getPriority());
        Thread.currentThread().setPriority(6);
        System.out.println("main thread end priority="+Thread.currentThread().getPriority());
        MyThread1 myThread1 =new MyThread1();
        myThread1.start();
    }
}
main thread begin priority=5
main thread end priority=6
myThread1 run priority=6
myThread2 run priority=6

1.10.2 优先级具有规则性

public class MyThread1 extends Thread{
    @Override
    public void run() {
        long beginTime = System.currentTimeMillis();
        for (int i =0; i <100; i++) {
            Random random =new Random();
            random.nextInt();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("★★★★★ thread1 use time=" +(endTime - beginTime));
    }
}
public class MyThread2 extends Thread{
    @Override
    public void run() {
        long beginTime = System.currentTimeMillis();
        for (int i =0; i <100; i++) {
            Random random =new Random();
            random.nextInt();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("☆☆☆☆☆ thread2 use time=" +(endTime - beginTime));
    }
}
public class Run{
    public static void main(String[] args) {
        for (int i =0; i <5; i++) {
            MyThread1 thread1 =new MyThread1();
            thread1.start();
            MyThread2 thread2 =new MyThread2();
            thread2.setPriority(6);
            thread2.start();
        }
    }
}

第一次执行结果:

☆☆☆☆☆ thread2 use time=0
★★★★★ thread1 use time=0
★★★★★ thread1 use time=0
☆☆☆☆☆ thread2 use time=0
☆☆☆☆☆ thread2 use time=0
★★★★★ thread1 use time=0
☆☆☆☆☆ thread2 use time=0
★★★★★ thread1 use time=4
★★★★★ thread1 use time=3
☆☆☆☆☆ thread2 use time=4

第二次执行结果:

★★★★★ thread1 use time=0
★★★★★ thread1 use time=0
★★★★★ thread1 use time=1
★★★★★ thread1 use time=0
☆☆☆☆☆ thread2 use time=0
★★★★★ thread1 use time=2
☆☆☆☆☆ thread2 use time=1
☆☆☆☆☆ thread2 use time=0
☆☆☆☆☆ thread2 use time=0
☆☆☆☆☆ thread2 use time=0

根据以上时长可以得出,不要把线程的优先级与运行结果的顺序作为衡量的标准,优先级较高的线程不一定每次都先执行完run()方法中的任务。他们的关系具有不确定性随机性

1.11 守护线程

Java中有两种线程,一种是用户线程,一种是守护线程
当进程中不存在费守护线程了,则守护线程自动销毁。典型的守护线程就是GC(垃圾回收器)。任何一个守护线程都是整个JVM中所有费守护线程的“保姆”,只要当前JVM实例中存在任何一个非守护线程没有结束,守护线程就在工作,当最后一个非守护线程结束时,守护线程才随着JVM一同结束工作。

public class MyThread extends Thread{
    private long i =0;
    @Override
    public void run() {
        try {
            while (true) {
                i++;
                System.out.println("i=" +i);
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class Run{
    public static void main(String[] args) {
        try {
            MyThread myThread =new MyThread();
            myThread.setDaemon(true);
            myThread.start();
            Thread.sleep(5000);
            System.out.println("main thread end, myThread end");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

相关文章

  • 初识Java多线程

    第一章 Java多线程技能 1)线程的启动;2)如何使线程暂停;3)线程的优先级;4)线程安全相关的问题 1.1 ...

  • java多线程初识3

    进程的概念 进程:官方的语言是计算机中的程序,关于某数据集合上的一次运行活动。使系统进行资源分配和调度的基本单位单...

  • 带你搞懂Java多线程(五)

    带你搞懂Java多线程(一)带你搞懂Java多线程(二)带你搞懂Java多线程(三)带你搞懂Java多线程(四) ...

  • 带你搞懂Java多线程(六)

    带你搞懂Java多线程(一)带你搞懂Java多线程(二)带你搞懂Java多线程(三)带你搞懂Java多线程(四)带...

  • Java多线程目录

    Java多线程目录 Java多线程1 线程基础Java多线程2 多个线程之间共享数据Java多线程3 原子性操作类...

  • iOS - 多线程(一):初识

    iOS - 多线程 系列文章 iOS - 多线程(一):初识iOS - 多线程(二):pthread、NSThre...

  • iOS - 多线程(二):pthread、NSThread

    iOS - 多线程 系列文章 iOS - 多线程(一):初识iOS - 多线程(二):pthread、NSThre...

  • iOS - 多线程(四):NSOperation

    iOS - 多线程 系列文章 iOS - 多线程(一):初识iOS - 多线程(二):pthread、NSThre...

  • iOS - 多线程(三):GCD

    iOS - 多线程 系列文章 iOS - 多线程(一):初识iOS - 多线程(二):pthread、NSThre...

  • Java多线程系列(一)——初识多线程

    前言 无论学习哪种开发语言,多线程都是绕不开的一个知识点。在Java学习中,掌握牢固的多线程知识更是进阶高级程序员...

网友评论

      本文标题:初识Java多线程

      本文链接:https://www.haomeiwen.com/subject/ryubihtx.html