JAVA多线程(1):多线程创建、状态和调度
发布日期:2021-07-30 03:26:01 浏览次数:3 分类:技术文章

本文共 16876 字,大约阅读时间需要 56 分钟。

一、进程与线程

1.进程和线程的由来

(1)串行:初级计算机只能串行执行任务,并且需要长时间等待用户输入

(2)批处理:预先将用户的指令集中成清单,批量串行处理用户指令,仍然无法并发执行
(3)进程:进程独占内存空间,保存各自运行状态,相互之间不干扰且可以互相切换,并为并发处理任务提供了可能
(4)线程:共享进程的内存资源,相互间切换更快捷,支持更细粒度的任务控制,使进程内的子任务得以并发执行。

2.进程和线程区别

总括:进程是资源分配的最小单位,线程是cpu调度的最小单位

 

进程

线程

独立应用

不能

独立的地址空间

有,相互不影响

无,只是进程的不同路径

独立的地址空间

切换开销

3.关系

(1)JAVA对操作系统提供的功能进行封装,包括进程和线程

(2)运行一个程序会产生一个进程,进程包含至少一个线程(主线程)
(3)每个进程对应一个JVM实例,多个线程共享JVM里的堆
(4)Java采用单线程变成模型,程序自动创建主线程
(5)主线程可以创建子线程,原则上主线程要后于子线程完成执行。

二、Runnable、Thread、Callable和线程池实现多线程

1.通过runnable接口实现多线程

package thread;public class mythread {    public static void main(String[] args) {        System.out.println("cuuurent thread:"+ Thread.currentThread().getName());        //测试实现接口线程:java.thread.mythreadofRunnable        //1.实现接口        Runnable threadrun=new mythreadofRunnable();        //2.通过接口实现Thread        Thread t1=new Thread(threadrun);        //3.通过(Thread)t1对象start运行方法        t1.start();        for (int i=0;i<10;i++){            System.out.println("线程外部方法第"+i+"次输出");        }    }}/** * 线程1 * 实现接口线程:java.thread.mythreadofRunnable * 实现方法:重写run方法 */class mythreadofRunnable implements Runnable{    public void  run(){        int count=0;        while (count<=10){            if (count%2==0){                System.out.println("count="+count);            }            count++;        }        System.out.println("cuuurent thread:"+ Thread.currentThread().getName());    }}

2.通过thread类实现多线程

package thread;public class mythread {    public static void main(String[] args) {        System.out.println("cuuurent thread:"+ Thread.currentThread().getName());        //测试实现接口线程:java.thread.mythreadofRunnable        //1.实现接口        Runnable threadrun=new mythreadofRunnable();        //2.通过接口实现Thread        Thread t1=new Thread(threadrun);        //3.通过(Thread)t1对象start运行方法        t1.start();        for (int i=0;i<10;i++){            System.out.println("线程外部方法第"+i+"次输出");        }        //测试集成thread类线程:java.thread.mythreadofThread        //1.实现mythreadofThread线程类        mythreadofThread t2=new mythreadofThread();        //2.通过(Thread)t2对象start运行方法        t2.start();        for (int i=0;i<10;i++){            System.out.println("线程外部方法第"+i+"次输出");        }    }}/** * 线程1 * 实现接口线程:java.thread.mythreadofRunnable * 实现方法:重写run方法 */class mythreadofRunnable implements Runnable{    public void  run(){        int count=0;        while (count<=10){            if (count%2==0){                System.out.println("count="+count);            }            count++;        }        System.out.println("cuuurent thread:"+ Thread.currentThread().getName());    }}/** * 线程2 * 继承Thread类:java.thread.mythreadofThread * 实现方法:重写run方法 */class mythreadofThread extends Thread{    int count=0;    public void  run(){        while (count<=10){            if (count%2==0){                System.out.println("count="+count);            }            count++;        }        System.out.println("cuuurent thread:"+ Thread.currentThread().getName());    }}

3.通过继承Collable类实现有返回值的多线程

package thread;import java.util.concurrent.Callable;public class mycallableNew implements Callable
{ int sum=0; public Integer call() throws Exception {// return null; String value="callable test"; System.out.println("Ready to work"); Thread.currentThread().sleep(3000); for (int i=0;i<10;i++){ sum+=i; } System.out.println("task done"); return sum; }}

测试代码

package thread;import java.util.concurrent.ExecutionException;import java.util.concurrent.Future;import java.util.concurrent.FutureTask;public class SyncDemo2 {    public static void main(String... args) {        mycallableNew mycallablenew=new mycallableNew();        FutureTask futureTask=new FutureTask(mycallablenew);        new Thread(futureTask).start();        try {            System.out.println(futureTask.get());        } catch (InterruptedException e) {            e.printStackTrace();        } catch (ExecutionException e) {            e.printStackTrace();        }    }}

结果:

Ready to work

task done
45

4.通过Executors.newFixedThreadPool线程池实现多线程提交

(1)execute:提交不要求有返回值的任务

(2)submit:提交有返回结果的任务,运行完返回结果

package thread;import java.util.ArrayList;import java.util.concurrent.*;public class threadpoolimp {    public static void main(String[] args) {        ExecutorService executorService= Executors.newFixedThreadPool(5);        //execute执行过程        //execute:不要求有返回值;submit提交有返回任务        executorService.execute(new Thread());        executorService.execute(new Runnable() {            @Override            public void run() {                System.out.println("implentment runnable!");            }        });        //submit提交有返回结果的任务,运行完返回结果        Future future=executorService.submit(new Callable
(){ @Override public String call() throws Exception { return "Callable thread;";// return null; } }); try { System.out.println(future.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } //将有返回值的线程的值,存进集合 ArrayList
list=new ArrayList<>(); for (int i = 0; i < 5; i++) { int finals=i; Future future1=executorService.submit(new Callable
() { @Override public String call() throws Exception { return "return is :"+finals; } }); try { list.add((String)future1.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } for (String s : list) { System.out.println(s); } }}

结果:

implentment runnable!Callable thread;return is :0return is :1return is :2return is :3return is :4

 

三、实现主线程等待子线程结束

1.目的

有的主线程程序,需要子线程运行结束的结果,从而实现精确控制。

2.方法一:主线程等待法

(1)原理:主线程通过监控子线程对应对象值,当子线程对象值被获取时,认为子线程执行完成;否则,主线程一直等待

(2)实现代码:

package thread;public class cyclewait implements Runnable {    private String value;    /**     * 等待7秒后再给value赋值     */    public void run() {        try {            Thread.currentThread().sleep(7000);        } catch (InterruptedException e) {            e.printStackTrace();        }        value="we have done now";    }    public static void main(String[] args) throws InterruptedException {        //1.创建子线程        cyclewait mcw=new cyclewait();        Thread t=new Thread(mcw);        //2.开启子线程        t.start();        //3.主线程等待        while (mcw.value==null){            Thread.currentThread().sleep(1000);        }        System.out.println("value : " +mcw.value);    }}

3.方法二:join方法

(1)原理:使用Thread类的join阻塞当前线程以等待子线程处理完毕

(2)代码

package thread;public class cyclewait implements Runnable {    private String value;    /**     * 等待7秒后再给value赋值     */    public void run() {        try {            Thread.currentThread().sleep(7000);        } catch (InterruptedException e) {            e.printStackTrace();        }        value="we have done now";    }    public static void main(String[] args) throws InterruptedException {        //1.创建子线程        cyclewait mcw=new cyclewait();        Thread t=new Thread(mcw);        //2.开启子线程        t.start();        //3.1主线程等待//        while (mcw.value==null){//            Thread.currentThread().sleep(1000);//        }//        System.out.println("value : " +mcw.value);        //3.2 join方法:主线程阻塞        t.join();        System.out.println("value : " +mcw.value);    }}

4.方法三:通过callable接口实现,通过FutureTask

(1)Callable类

package thread;import java.util.concurrent.Callable;public class mycallable implements Callable
{    public String call() throws Exception {//        return null;        String value="callable test";        System.out.println("Ready to work");        Thread.currentThread().sleep(3000);        System.out.println("task done");        return value;    }}

(2)通过futuretask实现

package thread;import java.util.concurrent.ExecutionException;import java.util.concurrent.FutureTask;public class mycallablefuturetaskimp {    public static void main(String[] args) throws ExecutionException, InterruptedException {        FutureTask
task=new FutureTask
(new mycallable());        new Thread(task).start();        if(!task.isDone()){            System.out.println("task has not finished, please wait!");        }        System.out.println("task return :"+ task.get());    }}

(3)通过线程池实现:通过线程池获取返回值

package thread;import java.util.concurrent.ExecutionException;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;public class mycallable_threadpoolimp {    public static void main(String[] args) {        ExecutorService newCachedThreadPool= Executors.newCachedThreadPool();        Future
future=newCachedThreadPool.submit(new mycallable());        //1.判断是否执行完,没有执行完,给出提示        if(!future.isDone()){            System.out.println("task has not finished, please wait");        }        //2.阻塞主线程,直到子线程执行结束        try {            System.out.println(future.get());        } catch (InterruptedException e) {            e.printStackTrace();        } catch (ExecutionException e) {            e.printStackTrace();        }finally {            newCachedThreadPool.shutdown();        }    }}

四、线程的状态

1.新建状态(New):创建后尚未启动的线程

2.运行(Runnable):

(1)Running:获得cpu资源,正在运行
(2)Ready:还没有获得cpu资源

3.阻塞

(1)无限期等待(Waiting):不会被分配CPU执行时间,需要显示被唤醒
(2)限期等待(Timed Waiting):在一定时间后会由系统自动唤醒
(3)阻塞(Blocked):等待获取排它锁

4.结束(Terminated):已终止线程的状态,线程已经结束执行。终止状态的线程不能重新启动。

五、线程调度

1.wait

作用:等待一定时间,让出cpu资源,并且释放同步锁lock。执行A,然后A通过wait释放同步锁,然后执行B,最后,等B执行完成后执行A。

package thread;public class waitandsleep {    public static void main(String[] args) {        final Object lock=new Object();        //线程A:执行wait逻辑        new Thread(new Runnable() {            public void run() {                System.out.println("Thread A is waiting to get the lock.");                synchronized (lock){                    try {                        System.out.println("thread A get lock");                        Thread.sleep(20);                        System.out.println("thread A do wait method");                        lock.wait(1000);//                        Thread.sleep(1000);                        System.out.println("thread A is done");                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        }).start();        //保证线程A先执行        try {            Thread.sleep(10);        } catch (InterruptedException e) {            e.printStackTrace();        }        //线程B:执行sleep逻辑        new Thread(new Runnable() {            public void run() {                System.out.println("Thread B is waiting to get the lock.");                synchronized (lock){                    try {                        System.out.println("thread B get lock");                        System.out.println("thread B is sleeping 10 ms");                        Thread.sleep(10);//                        lock.wait(10);                        System.out.println("thread B is done");                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        }).start();    }}执行结果:thread.waitandsleepThread A is waiting to get the lock.thread A get lockThread B is waiting to get the lock.thread A do wait methodthread B get lockthread B is sleeping 10 msthread B is donethread A is doneProcess finished with exit code 0

2.Sleep

作用:等待一定时间,但是不释放同步锁。执行过程时,A执行完成,再执行B

package thread;public class waitandsleep {    public static void main(String[] args) {        final Object lock=new Object();        //线程A:执行wait逻辑        new Thread(new Runnable() {            public void run() {                System.out.println("Thread A is waiting to get the lock.");                synchronized (lock){                    try {                        System.out.println("thread A get lock");                        Thread.sleep(20);                        System.out.println("thread A do wait method");//                        lock.wait(1000);                        Thread.sleep(1000);                        System.out.println("thread A is done");                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        }).start();        //保证线程A先执行        try {            Thread.sleep(10);        } catch (InterruptedException e) {            e.printStackTrace();        }        //线程B:执行sleep逻辑        new Thread(new Runnable() {            public void run() {                System.out.println("Thread B is waiting to get the lock.");                synchronized (lock){                    try {                        System.out.println("thread B get lock");                        System.out.println("thread B is sleeping 10 ms");//                        Thread.sleep(10);                        lock.wait(10);                        System.out.println("thread B is done");                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        }).start();    }}结果:thread.waitandsleepThread A is waiting to get the lock.thread A get lockThread B is waiting to get the lock.thread A do wait methodthread A is donethread B get lockthread B is sleeping 10 msthread B is doneProcess finished with exit code 0

3.通知notify或notifyall

(1)二者区别

notify:随机选取一个处于等待池中的线程进入锁池去竞争获取锁的机会

notifyAll:会让所有处于等待池的线程全部进入锁池去竞争获取锁的机会

(2)代码

package thread;public class waitandsleep_notify {    public static void main(String[] args) {        final Object lock=new Object();        //线程A:执行wait逻辑        new Thread(new Runnable() {            public void run() {                System.out.println("Thread A is waiting to get the lock.");                synchronized (lock){                    try {                        System.out.println("thread A get lock");                        Thread.sleep(20);                        System.out.println("thread A do wait method");                        //无限期等待,需要额外线程唤醒                        lock.wait();//                        Thread.sleep(1000);                        System.out.println("thread A is done");                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        }).start();        //保证线程A先执行        try {            Thread.sleep(10);        } catch (InterruptedException e) {            e.printStackTrace();        }        //线程B:执行sleep逻辑        new Thread(new Runnable() {            public void run() {                System.out.println("Thread B is waiting to get the lock.");                synchronized (lock){                    try {                        System.out.println("thread B get lock");                        System.out.println("thread B is sleeping 10 ms");                        Thread.sleep(10);//                        lock.wait(10);                        lock.notify(); //或者lock.notifyAll();                        System.out.println("thread B is done");                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        }).start();    }}

结果解释,线程B使用lock.notify(),通知正在阻塞的一个线程(当前线程A)进行继续执行

Thread A is waiting to get the lock.thread A get lockThread B is waiting to get the lock.thread A do wait methodthread B get lockthread B is sleeping 10 msthread B is donethread A is done

即如果线程B没有lock.notify(),则线程A不会持续进行,结果是

Thread A is waiting to get the lock.thread A get lockThread B is waiting to get the lock.thread A do wait methodthread B get lockthread B is sleeping 10 msthread B is done

4.yield:线程让步

(1)定义:当调用Thread.yield()函数时,当前线程可能会让出其占用的cpu资源,也可能不会让出其占用的cpu资源。同时,yield也不会释放锁lock,对锁的行为不会有影响。

(2)测试实例

package thread;public class yield {    public static void main(String[] args) {        Runnable yieldTask=new Runnable() {            public void run() {                for (int i=1;i<=20;i++){                    System.out.println(Thread.currentThread().getName()+i);                    if(i==5){                        Thread.yield();                    }                }            }        };        Thread t1=new Thread(yieldTask,"A");        Thread t2=new Thread(yieldTask,"B");        t1.start();        t2.start();    }}

结果:A线程当执行到i=5时,不一定会出让cpu资源。

A1A2A3A4A5B1B2A6B3B4A7B5A8A9A10A11A12B6A13B7A14B8B9A15B10A16A17A18A19A20B11B12B13B14B15B16B17B18B19B20

5.interrupt():中断线程

调用interrupt(),通知线程应该中断

(1)如果线程处于被阻塞状态,那么线程将立即退出被阻塞状态,并且抛出一个InterruptedException异常。
(2)如果线程处于正常活动状态,那么会将该线程的中断标志设置为true。被设置终端标志的线程将继续正常运行,不受影响。

 

转载地址:https://blog.csdn.net/u010886217/article/details/99696822 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Android 8 在service中弹出dialog失败
下一篇:(转)java本地调用cmd,shell命令,远程调用Linux执行命令方法总结

发表评论

最新留言

不错!
[***.144.177.141]2024年04月25日 05时39分39秒