java多线程_线程的基本操作

线程的常用操作方法,大都定义在Thread类中,包括一些重要的静态方法和实例方法。下面我们通过这篇文章来了解一些比较常用的方法。

sleep

sleep的作用是让当前正在执行的线程休眠。让cpu去执行其它的线程。

执行sleep方法后,线程的状态变为 TIME_WAITING (超时等待)。

public class Demo002_d {

        public static void main(String[] args) {
                testSleep();
                while (true){
                }
        }

        /**
         *
         * @desc sleep 方法学习
         * */
        public static void testSleep(){
                new Thread("testSleep"){
                        @Override
                        public void run() {
                                try {
                                        // testSleep 线程休眠2s
                                        Thread.sleep(200000);
                                } catch (InterruptedException e) {
                                        e.printStackTrace();
                                }
                        }
                }.start();
        }
}

interrupt

interrupt的作用是用来中断线程,其被设计用来替代stop()方法。

Thread.stop()用来停止线程,在JDK中已经被标记为过时方法;其最大的弊端在于强制终止正在运行的线程,相当于关闭计算机电源。如果正在运行的线程持有锁资源,那么会导致锁资源永远无法释放。所以JDK已经不推荐使用Thread.stop()来停止进程。

那么一个线程应该怎么样正确的终止线程了?当然,这个只有当事线程才知道。interrupt的设计正是于此,它不会终止线程,只是作为一个中断标识,告诉当前线程,父线程想要终止当前线程。至于怎样终止,则取决于当前线程本身。

中断阻塞线程

如果当前线程处于阻塞状态,则interrupt会让当前线程抛出InterruptedException异常;用户可以通过捕获InterruptedException异常来做一些处理。

public class Demo002_d {

        public static void main(String[] args) {
                Thread t1 = testinterrupt();
                t1.start();
                try {
                        Thread.sleep(2000);
                } catch (InterruptedException e) {
                        e.printStackTrace();
                }

                //main线程休眠2秒之后,中断t1线程
                t1.interrupt();

        }

        /**
         * @desc interrupt 中断休眠的线程
         * */
        public static Thread testinterrupt(){
                return new Thread("testinterrupt"){
                        @Override
                        public void run() {
                                try {
                                        Thread.sleep(200000);
                                } catch (InterruptedException e) {
                                        e.printStackTrace();
                                        System.out.println("哎,线程被中断了!!");
                                }
                        }
                };
        }
}

运行结果如下:
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at com.java.basic.thread.demo001.Demo002_d$1.run(Demo002_d.java:29)
哎,线程被中断了!!

中断正在运行的线程

如果线程正处于运行状态,线程不受任何影响;仅仅是线程的中断标记被设置为true,所以用户需要通过isInterrupted()获取中断标识,执行退出操作。

public class Demo002_d {

        public static void main(String[] args) {
                Thread t1 = testinterrupt1();
                t1.start();
                try {
                        Thread.sleep(2000);
                } catch (InterruptedException e) {
                        e.printStackTrace();
                }

                //main线程休眠2秒之后,中断t1线程
                t1.interrupt();

        }

        /**
         * @desc interrupt 中断正在运行的线程
         * */
        public static Thread testinterrupt1(){
                return new Thread("testinterrupt"){
                        @Override
                        public void run() {
                                while(true){
                                        if(isInterrupted()){
                                                System.out.println("线程被中断了...");
                                                return;
                                        }
                                }
                        }
                };
        }
}

join

join的作用是线程合并。

感觉线程的join和sql的join是比较类似的。假设有两个线程A和B,B线程的执行需要依赖A线程执行完成。join就是为这种场景设计的。join支持下面两种方式:

1、t.join() : 线程进入 WAITING 状态,直到t线程执行完毕,才能执行下面的代码。

2、t.join(2000) : 线程进入 TIME_WAITING 状态,主线程仅仅等待t线程执行 2000 毫秒,无论t线程是否执行完毕,都会执行下面的代码。

public class Demo002_d {

        public static void main(String[] args) {
                try {
                        testJoin();
                } catch (InterruptedException e) {
                        e.printStackTrace();
                }
        }

        /**
         *
         * @desc 线程合并测试
         * */
        public static void testJoin() throws InterruptedException {
                Thread a = new Thread("A"){
                        @Override
                        public void run() {
                                System.out.println("A 线程正在执行....");
                        }
                };
                a.start();
                a.join();

                Thread b = new Thread("B"){
                        @Override
                        public void run() {
                                System.out.println("B 线程正在执行....");
                        }
                };
                b.start();
                b.join();

                System.out.println("main 线程正在结束....");

        }
}

运行结果如下:
A 线程正在执行…
B 线程正在执行…
main 线程正在结束…

如上所示,无论你执行多少次,线程B都是在线程A结束之后才执行的。

yield

yield 会出让cpu的执行权限,出让执行权限之后,该线程进入RUNNABLE状态。重新加入cpu时间片段的竞争。

这里A、B线程每执行一次输出操作,就出让CPU执行权限,然后重新竞争CPU时间片。

public class Demo002_d {

        public static void main(String[] args) {
              testYield();

        }

        /**
         *
         * @desc yield 测试
         * */
        public static void testYield(){
                Thread a = new Thread("A"){
                        @Override
                        public void run() {
                                for(int i=0;i<5;i++) {
                                        System.out.println("A 线程正在执行....");
                                        Thread.yield();
                                }
                        }
                };
                Thread b = new Thread("B"){
                        @Override
                        public void run() {
                                for(int i=0;i<5;i++) {
                                        System.out.println("B 线程正在执行....");
                                        Thread.yield();
                                }
                        }
                };
                a.start();
                b.start();
        }
}

守护线程

Java中的线程分为2类,用户线程和守护线程;他们的区别是:

1、用户线程:当所有用户线程执行完成后,JVM进程才会停止;

2、守护线程: 当JVM进程停止的时候,守护线程就会停止;所以在守护线程中尽量不要去访问系统资源、连接数据库等。GC垃圾回收线程就是守护线程。

public class Demo002_d {

        public static void main(String[] args) {
                testDeamon();
                //主线程暂停2s
                try {
                        Thread.sleep(2000);
                } catch (InterruptedException e) {
                        e.printStackTrace();
                }
                System.out.println("主线程结束...");

        }

        /**
         * @desc 守护线程测试
         * */
        public static void testDeamon(){
                Thread deamon = new Thread("testDeamon"){
                        @Override
                        public void run() {
                                while(true){
                                        System.out.println("守护线程运行中......");
                                }
                        }
                };
                //设置为守护线程
                deamon.setDaemon(true);
                deamon.start();
        }
}

可以观察到,当主线程结束之后,守护线程立马结束,虽然我们没有去停止它。

需要注意的是:

1、守护线程必须在线程启动之前调用 setDaemon(true);
2、守护线程创建的线程也是守护线程;

线程设计模式(二阶段终止)

在java中怎么样终止线程了?

1、使用stop()方法停止线程: stop()方法会真正杀死线程,如果此时该线程持有锁,那么其他线程将永远无法获取锁。
2、使用System.exit()方法停止线程:会让整个进程都退出。
3、使用interrupt 两阶段终止:使用interrupt将线程的终止权力交给线程本身,本来是没有问题的。问题在于当被打断的线程处于阻塞状态的时候,阻塞线程会抛出InterruptedException,并将中断标识清空,无法停止线程。所以我们需要捕获InterruptedException异常,并重新将打断标识设置为true。

为了处理阻塞线程清空中断标识的问题,我们不得不在 catch 中重新打断。所以称为二阶段终止。

public class Demo002_d {

        public static void main(String[] args) {
                testTwoPhaseTermination();
        }

        public static void testTwoPhaseTermination(){
                Thread t1 =  new Thread("testTwoPhaseTermination"){
                        @Override
                        public void run() {
                                while(true){
                                        if(isInterrupted()){

                                                System.out.println("线程要关闭了...");
                                                break;
                                        }
                                        try {
                                                // 如果在阶段1被打断,会进入catch语句块,并且isInterrupted标志位清空,无法关闭线程
                                                Thread.sleep(1000); // 阶段1
                                                // 如果在阶段2被打断,线程的isInterrupted标志位为true,会捕抓到信号并关闭线程
                                                System.out.println("监控线程正在工作...."); // 阶段2
                                        } catch (InterruptedException e) {
                                                e.printStackTrace();
                                                // 需要重新设置isInterrupted标志位为true
                                                interrupt();
                                        }
                                }
                        }
                };
                t1.start();

                //主线程停止3秒
                try {
                        Thread.sleep(3000);
                } catch (InterruptedException e) {
                        e.printStackTrace();
                }
                //打断t1线程
                t1.interrupt();
        }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值