Java线程知识

Java线程知识

线程在多任务处理应用程序中有着至关重要的作用

概念

基本概念

进程:在操作系统中每个独立运行的程序就是一个进程

线程:程序执行的一个顺序执行流(程序的一个运行路径),一个进程至少有一个线程,线程拥有自己的堆栈、计数器和局部变量,多个线程共享所在进程的系统资源

并发:cpu在多个进程之间切换

并行:多个进程在多个不同cpu同时执行

多进程:多进程和多线程是多任务的两种类型,进程间数据块是相互独立的,进程间通过信号、管道等交互。

多线程:在多cpu计算机可以真正物理实现,单核计算机只是逻辑实现,由操作系统进行线程管理调度。

线程生命周期

新建 -> 就绪:start()
就绪 -> 运行:获得处理器资源
运行 -> 就绪:失去处理器资源
运行 -> 终止: 执行完成或者抛出异常,stop方法
运行 -> 阻塞: sleep,IO阻塞,等待同步锁,wait()等待其他线程通知(notify),suspend()挂起
阻塞 -> 就绪: sleep时间到了,IO方法返回,获得同步锁,收到notify()或notifyAll(),resume()恢复


//stop()容易造成死锁(该方法已过时)

Java线程模型

Thread类

继承Thread类,其中run()方法用于执行线程要执行的任务,start()方法用于启动线程

public class Mythread1 extends Thread {

    @Override
    public void run() {
        this.setName("我的线程02");
        System.out.println(this.getName());
    }

    public static void main(String[] args) {
        Mythread1 mythread1 = new Mythread1();
        mythread1.start();
        System.out.println(Thread.currentThread().getName());
    }
}

Runnable接口,实现Runnable接口

    public class MyThread2 implements Runnable {
        @Override
        public void run() {
            System.out.println("runnable");
        }

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

Callable接口,可以返回线程执行的值,通过FutureTask接收,FutureTask实现了RunnableFuture接口,实际上RunnableFuture继承了Runnable和Future接口,特别注意get()方法返回返回值,会造成阻塞

    import java.util.concurrent.*;

    public class MyCallable implements Callable<String> {
        private long waitTime;
        public MyCallable(int timeInMillis){
            this.waitTime=timeInMillis;
        }
        @Override
        public String call() throws Exception {
            Thread.sleep(waitTime);
            //return the thread name executing this callable task
            return Thread.currentThread().getName();
        }

    }

    class FutureTaskExample {
        public static void main(String[] args) {
            MyCallable callable1 = new MyCallable(1000);                       // 要执行的任务  
            MyCallable callable2 = new MyCallable(2000);

            FutureTask<String> futureTask1 = new FutureTask<String>(callable1);// 将Callable写的任务封装到一个由执行者调度的FutureTask对象  
            FutureTask<String> futureTask2 = new FutureTask<String>(callable2);

            ExecutorService executor = Executors.newFixedThreadPool(2);        // 创建线程池并返回ExecutorService实例  
            executor.execute(futureTask1);  // 执行任务  
            executor.execute(futureTask2);

            while (true) {
                try {
                    if(futureTask1.isDone() && futureTask2.isDone()){//  两个任务都完成  
                        System.out.println("Done");
                        executor.shutdown();                          // 关闭线程池和服务   
                        return;
                    }

                    if(!futureTask1.大专栏  Java线程知识 class="na">isDone()){ // 任务1没有完成,会等待,直到任务完成  
                        System.out.println("FutureTask1 output="+futureTask1.get());
                    }

                    System.out.println("Waiting for FutureTask2 to complete");
                    String s = futureTask2.get(200L, TimeUnit.MILLISECONDS);
                    if(s !=null){
                        System.out.println("FutureTask2 output="+s);
                    }
                } catch (InterruptedException | ExecutionException e) {
                    e.printStackTrace();
                }catch(TimeoutException e){
                    //do nothing  
                }
            }
        }
    }  

线程方法

run()线程执行的内容

start()启动线程

sleep()线程休眠指定时间,不会释放对象锁

isAlive()判断线程是否处于激活状态(就绪或运行)

join()是一个同步方法,父线程等待子线程执行指定时间(若为0则一直等待,直到子线程执行完毕),理解(join(),父线程获得同步代码块,wait一段时间,等待子线程执行完成或时间结束)

参考



 public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }


import static java.lang.Thread.currentThread;
import static java.lang.Thread.sleep;

public class TestJoin implements Runnable {


    public static void main(String[] sure) throws InterruptedException {
        Thread t = new Thread(new TestJoin());
        long start = System.currentTimeMillis();
        t.start();
        t.join(100);//等待线程t 1000毫秒
        System.out.println(System.currentTimeMillis()-start);//打印出时间间隔
        System.out.println("Main finished");//打印主线程结束
    }

    @Override
    public void run() {
       // synchronized (currentThread()) {
        for (int i = 1; i <= 5; i++) {
            try {
                sleep(1000);//睡眠5秒,循环是为了方便输出信息
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("睡眠" + i);
        }
        System.out.println("TestJoin finished");//t线程结束
    }
  // }
}


static void yield()暂停线程,并允许其他线程执行

线程优先级

线程优先级只是指获得资源的机会,并不是执行顺序

线程同步

synchronized

Java线程知识

小知识

多个线程访问同个对象的同步代码块时,同一时刻只能有一个线程得到执行

一个线程访问一个对象的同步代码块时,其他线程仍可以访问同步代码块

如果被锁的是类,那么无论new多少实例,同属一个类依然会被锁住,即线程之间通信依旧是同步的

需要注意的时synchronized关键字无法被继承,子类覆盖同步方法时,可以调用父类方法或显式加上关键字

定义接口方法不能使用synchronized,构造函数不能用synchronized,但可以用synchronized代码块

参考