Java并发编程-线程基础

2018-09-04  本文已影响12人  agile4j

参考资料:《Java高并发程序设计》


1.线程的基本操作

1.新建线程

1.继承Thread,重写run方法

 new Thread() {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
 }.start();

2.实现Runnable接口,以参数的形式传给Thread的构造方法

new Thread(()-> System.out.println(Thread.currentThread().getName())).start();

2.终止线程

1.被废弃的方法:stop()

2.正确的做法:让程序正常执行完毕自然退出

3.更强大的方式:线程中断

  1. // 中断线程
    public void Thread.interrupt()

  2. // 判断是否被中断
    public boolean Thread.isInterrupted()
    具体实现:

    return isInterrupted(false); // false表示不清除中断状态
    
  3. // 判断是否被中断,并清除当前中断状态
    public static boolean Thread.interrupted()
    具体实现:

    return currentThread().isInterrupted(true); // true表示清除
    
 while (true){
       if (Thread.currentThread().isInterrupted()){
           System.out.println("Interrupted!");
           break;
       }
       System.out.println("business code...");
 }
public static native void sleep(long millis) throws InterruptedException;
   while (true){
       if (Thread.currentThread().isInterrupted()){
           System.out.println("Interrupted!");
           break;
       }
       try {
           Thread.sleep(1000L);
       }catch (InterruptedException e){
           System.out.println("Interrupted When Sleep!");
           // break; //即时退出
           Thread.currentThread().interrupt(); //下次循环时退出
       }
   }

3.等待(wait)和通知(notify)

public final void wait() throws InterruptedException
public final native void notify();
public final native void notifyAll();
public class Test {
    private final static Object object = new Object();

    public static void main(String[] args) {
        new Thread(() -> {
            synchronized (object) { // 获得监视器
                System.out.println(System.currentTimeMillis() + " -- wait1 thread start!");
                try {
                    object.wait(); // 释放监视器
                                   // 当被唤醒后,会在这里重新尝试获得监视器
                    System.out.println(System.currentTimeMillis() + " -- wait1 thread end!");
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } // 释放监视器
        }).start();

        new Thread(() -> {
            synchronized (object) { // 获得监视器
                System.out.println(System.currentTimeMillis() + " -- wait2 thread start!");
                try {
                    object.wait(); // 释放监视器
                                   // 当被唤醒后,会在这里重新尝试获得监视器
                    System.out.println(System.currentTimeMillis() + " -- wait2 thread end!");
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } // 释放监视器
        }).start();

        try {
            Thread.sleep(1000); //确保两个wait线程都start之后再让notifyAll线程start
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            synchronized (object) { // 获得监视器
                System.out.println(System.currentTimeMillis() + " -- notifyAll thread start!");
                object.notifyAll();
                System.out.println(System.currentTimeMillis() + " -- notifyAll thread end!");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } // 释放监视器
        }).start();
    }
}
//输出:
//1531957572939 -- wait1 thread start!
//1531957572939 -- wait2 thread start!
//1531957573048 -- notifyAll thread start!
//1531957573048 -- notifyAll thread end!
//1531957575063 -- wait2 thread end!
//1531957577065 -- wait1 thread end!

4.被废弃的:挂起(suspend)和继续执行(resume)

  1. suspend()在导致线程暂停的同时,并不会释放任何 锁资源 。因此任何想要访问被它暂用了的锁的线程,都会被牵连。
  2. 如果resume()操作 意外 地在suspend()前就执行了,那么被挂起的线程可能很难有机会被继续执行。
  3. 对与被suspend()函数挂起的线程,它的 线程状态 还是Runnable,这会严重影响对系统状态的判断。
public class Test {
    public static final Object u = new Object();

    public static class MyThread extends Thread {
        public MyThread(String name) {
            super.setName(name);
        }
        @Override
        public void run() {
            synchronized (u) {
                System.out.println("in " + getName());
                Thread.currentThread().suspend();
                System.out.println("out " + getName());
            }
        }
    }
    
    public static void main(String[] args) throws InterruptedException {
        MyThread t1 = new MyThread("t1");
        MyThread t2 = new MyThread("t2");
        t1.start();
        Thread.sleep(100); // 为了确保t1的resume()发生在suspend()之后
        t2.start();
        t1.resume();
        t2.resume();
        t1.join();
        t2.join();
    }
}
// 输出:
// in t1
// out t1
// in t2

5.等待线程结束(join)

public class Test {
    public static void main(String[] args) {
        System.out.println(System.currentTimeMillis() + "main start");

        Thread preconditionThread = new Thread(() -> {
            try {
                System.out.println(System.currentTimeMillis() + "precondition start");
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                throw new UnsupportedOperationException();
            }
            System.out.println(System.currentTimeMillis() + "precondition finish");
        });

        preconditionThread.start();
        try {
            preconditionThread.join();
        } catch (InterruptedException e) {
            throw new UnsupportedOperationException();
        }

        System.out.println(System.currentTimeMillis() + "main finish");
    }
}
// 输出:
// 1534130381159main start
// 1534130381288precondition start
// 1534130383288precondition finish
// 1534130383289main finish

6.谦让(yield)

public static native void yield();

7.volatile关键字

8.synchronized

Thread t1 = new Thread(instance);
Thread t2 = new Thread(instance);
// 正确用法,使用的是一把锁

Thread tt1 = new Thread(new AccountingSyncBad());
Thread tt2 = new Thread(new AccountingSyncBad());
// 错误用法,使用的是两把锁

9.线程组

public class Test {
    public static void main(String[] args) {
        ThreadGroup printGroup = new ThreadGroup("PrintGroup");
        Runnable print = () -> System.out.println(Thread.currentThread().getName());
        Thread t1 = new Thread(printGroup, print, "T1");
        Thread t2 = new Thread(printGroup, print, "T2");
        t1.start();
        t2.start();
        System.out.println(printGroup.activeCount());
        printGroup.list();
    }
}
// activeCount()可以获得活动线程的总数,但由于线程是动态的,因此这个值只是一个估计值,无法准确确定。
// list()方法可以打印这个线程组中所有的线程信息,对调试有一定帮助。

10.守护线程Deamon

thread.setDaemon(true);
thread.start();
// 注意调用的顺序

11.线程优先级

public final static int MIN_PRIORITY = 1;
public final static int NORM_PRIORITY = 5;
public final static int MAX_PRIORITY = 10;

END

上一篇 下一篇

猜你喜欢

热点阅读