zoukankan      html  css  js  c++  java
  • Java 线程的基本使用

    GitHub Page: http://blog.cloudli.top/posts/Java-线程的基本使用/

    创建线程

    创建线程的方式有两种:

    • 继承 Thread
    • 实现 Runnable 接口

    Thread 类实现了 Runnable 接口。使用继承 Thread 类的方式创建线程时,最大的局限是不支持多继承。所以为了支持多继承,应该使用实现 Runnable 接口的方式。两种方式创建的线程在工作时是一样的,没有本质区别。

    第一种方式,继承 Thread 类并重写 run() 方法:

    public class Work extends Thread {
        
        @Override
        public void run() {
            System.out.println("Working...");
        }
    }
    
    public class Run {
        public static void main(String[] args) {
            Work work = new Work();
            work.start();
            System.out.println("End!");
        }
    }
    

    运行结果可能 “End!”先输出。在使用多线程时,运行结果与调用顺序是无关的。

    调用 run() 方法只是普通的方法调用,不会启动线程。如果多次调用 start() 方法,会抛出 IllegalThreadStateException 异常。

    第二种方式,实现 Runnable 接口:

    public class Work implements Runnable {
        
        @Override
        public void run() {
            System.out.println("Working...");
        }
    }
    
    public class Run {
        public static void main(String[] args) {
            Thread t = new Thread(new Work());
            t.start();
            System.out.println("End!");
        }
    }
    

    这种方式与第一种在运行上没有什么区别。其优点在于突破了单继承的限制。

    Thread 类的部分构造方法:

    构造方法 说明
    Thread() 创建一个新的线程
    Thread(String name) 创建一个新的线程,并指定名称
    Thread(Runnable target) 创建一个新的线程,将 target 作为运行对象
    Thread(Runnable target, String name) 将 target 作为运行对象,并指定名称
    Thread(ThreadGroup group, Runnable target) 将 target 作为运行对象,并作为线程组的一员

    线程的方法

    currentThread() 方法

    currentThread() 方法返回正在被执行的线程的信息。

    public class Run() {
        public static void main(String[] args) {
            System.out.println(Thread.currentThread().getName());
        }
    }
    

    以上代码在控制台输出 “main“,说明该方法被名为 main 的线程调用。

    import static java.lang.System.out;
    
    public class Run {
    
        static class Work extends Thread {
        
            @Override
            public void run() {
                out.printf("%s 被调用
    ", currentThread().getName());
            }
        }
    
        public static void main(String[] args) {
            Work t1 = new Work(),
                    t2 = new Work();
            t1.start();
            t2.start();
        }
    }
    

    以上代码运行结果:

    Thread-0 被调用
    Thread-1 被调用
    
    Process finished with exit code 0
    

    run() 方法中可以省略 Thread 直接调用 currentThread() 方法。

    isAlive() 方法

    该方法判断当前线程是否处于活动状态。

    import static java.lang.System.out;
    
    public class Run {
    
        static class Work extends Thread {
        
            @Override
            public void run() {
                out.printf("运行中 %s
    ", isAlive());
            }
        }
    
        public static void main(String[] args) throws Throwable {
            Work t = new Work();
            out.printf("运行前: %s
    ", t.isAlive());
            t.start();
            // 等待线程运行完成
            Thread.sleep(1000);
            out.printf("运行结束: %s
    ", t.isAlive());
        }
    }
    

    以上代码运行结果:

    运行前: false
    运行中 true
    运行结束: false
    
    Process finished with exit code 0
    

    sleep() 方法

    sleep() 方法指定毫秒数让当前线程休眠(暂停运行),该操作不会释放锁

    停止线程

    interrupt() 方法

    interrupt() 方法并不能立刻停止线程,只是在在线程中打了一个停止的标记。

    import static java.lang.System.out;
    
    public class StopThread {
    
        static class Work extends Thread {
    
            @Override
            public void run() {
                for (int i = 1; i <= 50000; i++) {
                    out.printf("i = %d
    ", i);
                }
            }
        }
    
        public static void main(String[] args) throws Throwable {
            Work work = new Work();
            work.start();
            Thread.sleep(200);
            work.interrupt();
            out.println("Call interrupt!");
        }
    }
    

    以上代码运行结果:

    ...
    i = 8190
    i = 8191
    i = 8192
    Call interrupt!
    i = 8193
    i = 8194
    i = 8195
    ...
    

    interrupt() 方法调用后,线程仍在运行。

    要使用 interrupt() 方法停止线程,需要在线程中判断中断状态,有两个方法:

    • interrupted():测试当前线程是否是中断状态,执行后将状态清除,设置为 false
    • isInterrupted():作用同上,但是不清除状态。
    import static java.lang.System.out;
    
    public class StopThread {
    
        static class Work extends Thread {
    
            @Override
            public void run() {
                for (int i = 1; i <= 50000; i++) {
                    if (isInterrupted()) {
                        out.println("跳出循环!");
                        break;
                    }
                    out.printf("i = %d
    ", i);
                }
            }
        }
    
        public static void main(String[] args) throws Throwable {
            Work work = new Work();
            work.start();
            Thread.sleep(200);
            work.interrupt();
            out.println("Call interrupt!");
        }
    }
    

    以上代码执行结果:

    ...
    i = 8301
    i = 8302
    i = 8303
    i = 8304
    i = 8305
    i = 8306
    i = 8307
    Call interrupt!
    跳出循环!
    
    Process finished with exit code 0
    

    在调用 interrupt() 方法后,循环已经退出。但是这种方式只是跳出了循环,假如 for 循环外还有代码,仍然会执行。

    抛出异常停止线程

    可以在判断线程状态为中断时,抛出一个异常,在 catchfinally 块中做中断后的处理:

    import static java.lang.System.out;
    
    public class StopThread {
    
        static class Work extends Thread {
    
            @Override
            public void run() {
                try {
                    for (int i = 1; i <= 50000; i++) {
                        if (isInterrupted()) {
                            out.println("Interrupted!");
                            throw new InterruptedException("抛出异常!");
                        }
                        out.printf("i = %d
    ", i);
                    }
                    out.println("for 循环结束!");
                } catch (InterruptedException e) {
                    out.println(e.getMessage());
                }
            }
        }
    
        public static void main(String[] args) throws Throwable {
            Work work = new Work();
            work.start();
            Thread.sleep(200);
            work.interrupt();
            out.println("Call interrupt!");
        }
    }
    

    以上代码将线程要执行的任务放入 try 块中,当判断为中断状态时,抛出 InterruptedException ,如果需要释放锁,可以在 finally 块中执行。

    也可以配合 return 来停止线程:

    if (isInterrupted()) {
        return;
    }
    

    暂停线程

    Java 提供了 suspend()resume() 方法来暂停和恢复线程,不过这两个方法已经过期作废了。

    suspend() 方法暂停线程时,不会释放锁。所以使用 suspend() 方法容易产生死锁。

    如果需要暂停线程,可以加入一个标记,若标记指出线程需要暂停,使用 wait() 进入等待状态,如需要恢复,使用 notify() 唤醒。

    import static java.lang.System.out;
    
    public class StopThread {
    
        static class Work extends Thread {
            // 暂停标记
            private boolean isSuspended = false;
    
            void pause() {
                isSuspended = true;
            }
    
            synchronized void wake() {
                isSuspended = false;
                // 唤醒
                this.notify();
                out.println("已唤醒!");
            }
    
            @Override
            public void run() {
                synchronized (this) {
                    try {
                        for (int i = 1; i <= 5000; i++) {
                            if (isInterrupted()) {
                                return;
                            }
    
                            if (isSuspended) {
                                out.println("已暂停!");
                                // 等待
                                this.wait();
                            }
    
                            out.printf("%s i = %d
    ", getName(), i);
                        }
                        out.printf("%s end!
    ", getName());
                    } catch (InterruptedException e) {
                        out.println(e.getMessage());
                    }
                }
            }
        }
    
        public static void main(String[] args) throws Throwable {
            Work work = new Work();
            work.start();
            Thread.sleep(100);
            // 暂停
            work.pause();
            Thread.sleep(100);
            // 唤醒
            work.wake();
        }
    }
    

    以上代码使用 wait()notify() 暂停与恢复线程。运行结果:

    ...
    Thread-0 i = 202
    Thread-0 i = 203
    Thread-0 i = 204
    已暂停!
    已唤醒!
    Thread-0 i = 205
    Thread-0 i = 206
    Thread-0 i = 207
    ...
    Thread-0 i = 4998
    Thread-0 i = 4999
    Thread-0 i = 5000
    Thread-0 end!
    
    Process finished with exit code 0
    

    yield 方法

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

    import static java.lang.System.currentTimeMillis;
    import static java.lang.System.out;
    
    public class Yield {
        static class Work extends Thread {
    
            @Override
            public void run() {
                long before = currentTimeMillis();
                int sum = 0;
                for (int i =1; i < 2000000; i++) {
                    // yield();
                    sum += (i + 1);
                }
                long after = currentTimeMillis();
                out.printf("Cost: %dms
    ", after - before);
            }
        }
    
        public static void main(String[] args) {
            new Work().start();
        }
    }
    

    以上代码不使用 yield() 方法时大概 15ms 执行完,加上后大概有 500ms。

  • 相关阅读:
    关于禁用发布可能出现的问题处理
    SQL Server数据库的整理优化的基本过程(一)
    分享SQL2005分区实现教程
    Oracle数据库的测试用户Scott的密码为什么是Tiger?
    这就是传说中的搜狗浏览器2.0
    IE6,IE7下双倍边距续
    IE7下fload:left造成双倍边距BUG
    as2和as3之间交互
    倒计时效果
    js拖动层效果
  • 原文地址:https://www.cnblogs.com/cloudfloating/p/11719219.html
Copyright © 2011-2022 走看看