多线程线程——基础API

2018-10-16  本文已影响0人  我不懂我不懂a

线程的创建

创建线程有三种方式 thread,runnable,callable。

  1. 继承Thread类
public class Test1 extends Thread{
    public static void main(String[] args) {
          Test1 test = new Test1();
          test.start();
    }

    @Override
    public void run(){
        //do something
    }
}

  1. 实现Runnable接口
public class Test2 implements Runnable {

    public static void main(String[] args) {
        Thread t1 = new Thread(new Test2());
        t1.start();
    }

    @Override
    public void run() {
        //do something
    }
}
  1. 实现Callable接口
public class Test3 implements Callable<Integer> {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<Integer> task = new FutureTask<Integer>(new Test3());
        new Thread(task).start();

        Integer result = task.get();
        System.out.println(result);

    }

    @Override
    public Integer call() throws Exception {
        //dosomething
        return 0;
    }
}

Callable是泛型接口,泛型中的类型正是调用call返回的类型。

为什么使用Runnable而不是Thread
答:

  1. 使用类继承Thread 不适合资源共享,
  2. 避免Java中单继承的限制
  3. 增加程序的健壮性,代码可以被多个线程共享,代码和数据独立

Runnable和Callable的区别
答: Callable接口支持返回执行结果,Runnable不行。Callable接口的call()可以抛出异常V call() throws Exception; Runnable的run()只能内部捕获处理。

run() 和 start()的区别
答:由代码可以看到,run方法只是调用了target的run方法,还是在主线程中运行并未开启新的线程。而start()调用后,启动了新的线程。

public
class Thread implements Runnable {
    /* What will be run. */
    private Runnable target;

    @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }
}

线程的中断

Thread# void interrupt 向线程发送中断请求,将中断flag置为true
Thread# static boolean interrputed 测试线程是否为中断状态,重置中断flag为false
Thread# isInterrputed 测试线程是否为中断状态,不会重置中断flag

正确的使用interrupt终止线程的姿势

    public void run() {
        while(!Thread.currentThread().isInterrupted()){
            System.out.println("...");
            Thread.currentThread().interrupt();
        }
    }

wait()和notify()/notifyAll()

wait和notify/notifyAll都是Object类的方法
一个线程调用了object.wait( )后,这个线程就会进入该共享资源的等待队列,释放共享资源的锁。
调用了object.notify( )后,会随机唤醒该资源的等待队列中随机一个线程(唤醒后线程并不能立即进入可运行状态(Runnable),而是进入阻塞状态(Blocked)等待获得锁)


image.png image.png

wait 和notify/notifyAll都需要在synchronized语句中才能执行。

注意:IllegalMonitorStateException
synchronized锁住的对象应该和调用wait与notify一样。

/**
 * wait 和 notify/notifyAll的demo
 * 生产者消费者模型
 * Created by tjc on 2018-10-16.
 */
public class Test5 {

    int count = 0;

    public static void main(String[] args) {
        Test5 test5 = new Test5();

        new Thread(new Product(test5)).start();
        new Thread(new Customer(test5)).start();
    }

}

class Product implements Runnable {

    Test5 test5 = null;

    Product(Test5 test5){
        this.test5 = test5;
    }

    @Override
    public void run() {
        synchronized (test5) {
            while (true) {
                while (test5.count >= 5) {
                    try {
                        test5.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                test5.count++;
                if(test5.count>=5) test5.notifyAll();

                System.out.println(test5.count);
            }
        }
    }
}

class Customer implements Runnable {

    Test5 test5 = null;

    Customer(Test5 test5){
        this.test5 = test5;
    }
    @Override
    public void run() {
        synchronized (test5) {
            while (true) {
                while (test5.count <= 0) {
                    try {
                        test5.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                test5.count--;
                if(test5.count<=0) test5.notifyAll();
                System.out.println(test5.count);
            }
        }
    }
}

注意:wait通常和while一起使用

wait和sleep的区别
答:wait 会释放锁,sleep不会

yield() 和 join()

yield让优先级更高的线程执行
join让调用线程先执行

上一篇下一篇

猜你喜欢

热点阅读