java多线程(一)

Java线程

运行的一个java程序会产生一个进程,一个java进程对应一个jvm实例,每个线程可以共享JVM里的堆,java是单线程编程模型

Thread的start和run的区别

start方法会创建一个新的子线程并启动
run方法只是Thread的一个普通调用
就是start会创建一个新线程,而run并不会创建一个新的线程

Thread和Runnable的区别

最明显,thread是一个类。而runnable是一个接口。
thread通过提供一个参数为Runnable的有参构造,使其鞥实现多线程,由于单一继承原则,推荐使用runnable接口

处理线程返回值

  1. 主线程等待法
    对要获取的变量进行循环等待,当变量为需要的值时跳出循环。
  2. 使用threa类的join()阻塞当前线程,让子线程处理完毕
  3. 通过Callable接口实现,通过FutureTask或者线程池实现
//通过Callable接口实现
public class MyCallable  implements Callable<String>{
    @Override
    public String call() throws Exception {
        String value = "test";
        System.out.println("ready to work");
        Thread.currentThread().sleep(5000);
        System.out.println("done");
        return value;
    }
}
public class FutureTaskDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<String> task = new FutureTask<String>(new MyCallable());
        new Thread(task).start();
        if(!task.isDone()) {
            System.out.println("not finished");
        }
        System.out.println(task.get());
    }
}

thread中存在含有存在runnable参数的构造函数,没有callable接口的构造函数,java提供了FutureTask类,它实现了RunnableFuture接口,而该接口继承了Runnable, Future类,FutureTask中有callable为参数的构造,因此使用FutureTask使集合了runnable和callable

FutureTask构造函数中有callable为参数
在这里插入图片描述
FutureTask实现了RunnableFuture接口
在这里插入图片描述
RunnableFuture接口继承了Runnable, Future类
在这里插入图片描述
通过线程池获取

public class ThreadPoolDemo {
    public static void main(String[] args) {
        ExecutorService threadpool = Executors.newCachedThreadPool();
        Future<String> future = threadpool.submit(new MyCallable());
        if (!future.isDone()) {
            System.out.println("wait");
            try {
                System.out.println(future.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            } finally {
                 threadpool.shutdown();
            }
        }
    }
}

线程状态

共有六个状态

  1. 新建di’a
  2. 运行:包含正在运行和等待运行
  3. 无限期等待:不会分配时间执行,需要显示进行唤醒(可使用notify或者notifyAll)
  4. 限期等待:可以自动唤醒,由系统自动唤醒
  5. 阻塞:获取排他锁
  6. 结束:线程终止

在终止的线程上 调用start方法会报illegalStateException异常

sleep和wait的区别

  1. sleep是Thread类的方法,wait是Object类的方法
  2. sleep可以在任何时候调用
  3. wait只能在synchronized方法或者synchronized块中使用
  4. sleep只会让出cpu但是不会放弃锁
  5. wait会让出cpu并且释放占有的同步资源锁
//验证第五和第六
public class WaitSleepDemo {
    public static void main(String[] args) throws InterruptedException {
        final Object lock = new Object();
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("thread is waittong");
                synchronized (lock){
                    System.out.println("get lock");
                    try {
                        Thread.sleep(20);
                        System.out.println("thread wait");
                        lock.wait(1000);
                        System.out.println("thread done");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }
            }
        }).start();
        Thread.sleep(10);
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("threadb is waittong");
                synchronized (lock){
                    System.out.println("getb lock");
                    try {
                        System.out.println("threadb is sleeping");
                        Thread.sleep(20);
                        System.out.println("threadb done");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }
            }
        }).start();
    }
}

第一个线程采用的的wait,会释放获取的锁哦和cpu,因此第二个线程获取了锁,由于第二个线程使用的是sleep所以只释放cpu等到醒来后继续执行完第二个线程,期间不释放锁。当第二个线程结束时释放锁。此时第一个线程才能执行,最后第一个线程执行完毕。运行结果如下
在这里插入图片描述

notify&notifyAll

锁池 EntryList

当线程A已经获得了某个对象的锁。其他线程速想要调用这个对象的synchronized方法或块时必须要获取该对象的锁,但该锁已被线程A占用,此时其他线程会进入该对象的锁池

等待池 WaitSet

线程A调用了对象的wait方法,就会释放该对象的锁,同时线程A进入对象的等待池中,等待池中的线程不会竞争该对象的锁

notifyAll让所有在等待池中的线程进入锁池获取竞争锁的能力
notify随机选取一个在等待池中的线程进入锁池

yield

当调用yield函数,表示当前 线程愿意让出cpu
调度,但有此时线程调度器选择是否继续进行,不会对锁进行影响(就是说你愿意让出cpu是你的事,但是我是否同意你让出cpu是我的事)

interrupt

如何中断线程呢?

  1. 调用stop方法停止线程(不用)
  2. 调用suspend和resume (不用)
  3. 调用interrupt

调用interrupt方法,如此时线程被阻塞,线程会立即退出阻塞状态进入活跃状态,并且抛出InterruprtedException异常,如果线程为活跃状态,就修改中断标志为true。此时线程正常运行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值