Java并发基础

并发,指的是多道程序交替执行,单核并发可以让用户感觉到是多个程序同时执行。而多核则可以真正实现进程的同时运行。

线程

线程的目的是为了执行某个任务,每条线程都认为自己独占CPU和内存。

创建线程

创建线程有三种方式 继承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 API

    public static native Thread currentThread()
    public final void join() throws InterruptedException
    public static native void yield()
    public static native void sleep(long millis) throws InterruptedException
    public void interrupt()
    public boolean isInterrupted()
    public static boolean interrupted()

Object API

    public final void wait() throws InterruptedException
    public final native void notifyAll()
    public final native void notify()

线程的中断

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通常和while一起使用

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


/**
 * 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);
            }
        }
    }
}

yield() 和 join()

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

生命周期

Thread状态
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 进程和线程 进程 所有运行中的任务通常对应一个进程,当一个程序进入内存运行时,即变成一个进程.进程是处于运行过程中...
    胜浩_ae28阅读 10,537评论 0 23
  • 单任务 单任务的特点是排队执行,也就是同步,就像再cmd输入一条命令后,必须等待这条命令执行完才可以执行下一条命令...
    Steven1997阅读 4,980评论 0 6
  • 要阐释空,仰望空,逼近空,触及空,必须运用一系列的减法和否定之法。”心经虽然简短,却用了大量的否定词,例如不和无的...
    慢慢树阅读 1,391评论 0 0
  • 今天要和大家分享的书是[美]泰勒·本-沙哈尔的《幸福的方法》。 001.积极心里学 追求幸福是每一个人的终极目标,...
    心的芳香阅读 845评论 0 0
  • 当我为一地阳光感恩时,心中的力量就会升起。拥有的一切都成为白白的赐予,而不是自己必须得到的。于是,每欣赏到的一个美...
    息影微光阅读 851评论 0 1