线程基础知识

Posted 罗贱人

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程基础知识相关的知识,希望对你有一定的参考价值。

线程基础知识(一)

看了Java多线程编程核心技术第一章,算是读后感吧感觉自己基础并不是很好。

并发和并行

并发:你在吃饭突然来了一个电话,然后你去接电话,接完电话再吃饭。

并行:你在吃饭突然来了一个电话,然后你边吃饭边接电话。

并发其实就是交替的进行,并行就是同时进行。

进程和线程和程序

参考https://blog.csdn.net/woaigaolaoshi/article/details/51039505

程序并不能单独执行,只有将程序加载到内存中,系统为他分配资源后才能够执行,这种执行的程序称之为进程,也就是说进程是系统进行资源分配和调度的一个独立单位,每个进程都有自己单独的地址空间。所以说程序与进程的区别在于,程序是指令的集合,是进程运行的静态描述文本,而进程则是程序在系统上顺序执行时的动态活动。

但是进程存在着很多缺陷,主要集中在两点:

(1).进程只能在同一时间干一件事情,如果想同时干两件事或多件事情,进程就无能为力了。

(2).进程在执行的过程中如果由于某种原因阻塞了,例如等待输入,整个进程就会挂起,其他与输入无关的工作也必须等待输入结束后才能顺序执行。

为了解决上述两点缺陷,引入了线程这个概念。

线程是进程的一个实体,也是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位,有时又被称为轻权进程或轻量级进程,相对进程而言,线程是一个更加接近于执行体的概念,进程在执行过程中拥有独立的内存单元,而线程自己基本上不拥有系统资源,也没有自己的地址空间,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),线程的改变只代表了 CPU 执行过程的改变,而没有发生进程所拥有的资源变化。除了CPU 之外,计算机内的软硬件资源的分配与线程无关,但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。

举个例子吧,QQ是腾讯的一个应用也是一个程序,当我们双击QQ输入账号和密码点击登录时(将程序加载到内存中,系统为他分配资源)这就是一个进程。你可以打开任务管理器查看下。

要是你想找小明同学聊天,小红同学聊天...打开的窗口就是线程。

Thread类和Runnable接口

继承Thread类重写run()方法

class MyThread extends Thread{
@Override
public void run(){
    System.out.println(Thread.currentThread().getName());
}

实现Runnable接口

class MyRunnable implements Runnable{

@Override
public void run() {
    System.out.println("myRunnable:"+Thread.currentThread().getName());
}
}

public class Test {
public static void main(String[] args) {
    MyThread thread=new MyThread();
    thread.start();
    Thread thread1=new Thread(new MyRunnable());
    thread1.start();
}
}

推荐使用Runnable,因为java是单继承有局限性,而接口是多"继承"(实现多个接口)。

几个方法

currentThread()获取当前线程

public class Test {
public static void main(String[] args) {
    System.out.println(Thread.currentThread().getName());
}
}

isAlive()方法判断当前线程是否活着

public class Test {
public static void main(String[] args) {
    MyThread thread=new MyThread();
    thread.start();
    System.out.println(thread.isAlive());
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println(thread.isAlive());

}
}

class MyThread extends Thread{
@Override
public void run(){
    System.out.println(Thread.currentThread().getName());
}
} 


sleep()当前线程休眠让出cpu使用,但是不让出锁 wait 会让出锁使用

public class Test {
    public static void main(String[] args) {
        MyRunnable runnable=new MyRunnable();
        Thread thread=new Thread(runnable);
        Thread thread1=new Thread(runnable);
        Thread thread2=new Thread(runnable);
        Thread thread3=new Thread(runnable);
        Thread thread4=new Thread(runnable);
        Thread thread5=new Thread(runnable);
        thread.start();
        thread1.start();
        thread2.start();
        thread3.start();
        thread4.start();
        thread5.start();
    }
}

class MyRunnable implements Runnable{

    @Override
    public void run() {
        synchronized (Test.class) {
            System.out.println("myRunnable:" + Thread.currentThread().getName());
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}



public class TestThread {
    public static void main(String[] args) {
        MyThread myThread=new MyThread();
        Thread thread1=new Thread(myThread);
        Thread thread2=new Thread(myThread);
        Thread thread3=new Thread(myThread);
        Thread thread4=new Thread(myThread);
        Thread thread5=new Thread(myThread);
        Thread thread6=new Thread(myThread);
        thread1.start();
        thread2.start();
        thread3.start();
        thread4.start();
        thread5.start();
        thread6.start();

    }
}

class MyThread extends Thread{

    @Override
    public synchronized void run(){
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName());
    }
}


wait(),notify(),notifyAll()是属于Object类中。调用这3个方法时需要持有当前对象锁资源不然会有java.lang.IllegalMonitorStateException 异常

生产者消费者。

public class PCModel {
    public static void main(String[] args) {
        //初始化storeHouse的大小
        int storeHouseSize=10;
        PriorityQueue<Integer> storeHouse=new PriorityQueue<>(storeHouseSize);
        Thread producer=new Thread(new Producer(storeHouse));
        Thread consumerOne=new Thread(new Consumer(storeHouse));
        Thread consumerTwo=new Thread(new Consumer(storeHouse));
        producer.start();
        consumerOne.start();
        consumerTwo.start();


    }



}

class Consumer implements Runnable{
    private Queue<Integer> storeHouse;
    public Consumer(Queue<Integer> storeHouse){
        this.storeHouse=storeHouse;
    }
    @Override
    public void run() {
        consume();
    }

    private void consume(){
        while(true){
            synchronized (storeHouse){
                while(storeHouse.size()==0){
                    try {
                        storeHouse.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //出队列
                storeHouse.poll();
                System.out.println(Thread.currentThread().getName()+"消费了一个");
                storeHouse.notifyAll();
            }
        }
    }
}


class Producer implements Runnable{
    private Queue<Integer> storeHouse;
    public Producer(Queue<Integer> storeHouse){
        this.storeHouse=storeHouse;
    }
    @Override
    public void run() {
        produce();
    }

    private void produce(){
        while (true){
            synchronized (storeHouse){
                while (storeHouse.size()==10){
                    try {
                        storeHouse.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //生产
                storeHouse.add(1);
                System.out.println(Thread.currentThread().getName()+"添加了一个");
                storeHouse.notifyAll();
            }
        }
    }
}


getId()获取线程的唯一标识

/**
 * Returns the identifier of this Thread.  The thread ID is a positive
 * <tt>long</tt> number generated when this thread was created.
 * The thread ID is unique and remains unchanged during its lifetime.
 * When a thread is terminated, this thread ID may be reused.
 *
 * @return this thread\'s ID.
 * @since 1.5
 */
public long getId() {
    return tid;
}

interrupted(),isInterrupted(),interrupt()

public class TestThread {
    public static void main(String[] args) {
        MyThread myThread=new MyThread();
        myThread.start();
        System.out.println(myThread.isInterrupted());
        myThread.interrupt();
        System.out.println(myThread.isInterrupted());

    }
}

class MyThread extends Thread{

    @Override
    public synchronized void run(){
        for(int i=1;i<1000;i++){
            System.out.println(Thread.currentThread().getName()+"     "+i);
        }
    }
}

interrupt()不能停止线程,只是在打个停止的标记。isInterrupted()判断线程是否已经中断。

public class TestThread {
    public static void main(String[] args) {
        Thread.currentThread().interrupt();
        System.out.println(Thread.interrupted());
        System.out.println(Thread.interrupted());
    }
}

interrupted()判断当前线程是否中断。interrupted()具有清除状态功能。如上面结果第二次调用返回false。


线程在wait或sleep期间被中断会抛出InterruptedException

public class TestThread {
    public static void main(String[] args) {
        MyThread myThread=new MyThread();
        myThread.start();
        myThread.interrupt();
    }
}

class MyThread extends Thread{

    @Override
    public synchronized void run(){
        try {
            Thread.sleep(10000);
            //this.wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

一般当你调用sleep()方法或wait()方法后会自动提示你有异常要处理。


stop()方法为什么被抛弃

public class TestThread {
    public static void main(String[] args) {
        Person person=new Person("aaaaaaaaaa","1");
        MyThread myThread=new MyThread(person);
        myThread.start();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        myThread.stop();
        System.out.println(person.getName()+"    "+person.getAge());

    }
}

class MyThread extends Thread{
    private Person person;

    public MyThread(Person person){
        this.person=person;
    }

    @Override
    public synchronized void run(){
        System.out.println(person.getName()+"    "+person.getAge());
        person.setName("abcd");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        person.setAge("20");
        System.out.println(person.getName()+"    "+person.getAge());

    }
}

class Person{
    //姓名
    private String name;
    //年龄
    private String age;

    public Person(String name, String age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }
}

stop()方法会造成数据不一致。


suspend()和resume()方法为什么被抛弃

public class TestThread {
    public static void main(String[] args) {
        Person person = new Person("aaaa", 15);
        MyRunnable myRunnable = new MyRunnable(person);
        Thread thread = new Thread(myRunnable);
        thread.start();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        person.setName("xiaoming");
        Thread thread1 = new Thread(new MyRunnable(person));
        thread1.start();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        person.setName("AAAA");
        Thread thread2 = new Thread(new MyRunnable(person));
        thread2.start();


    }
}

class MyRunnable implements Runnable {
    private Person person;

    public MyRunnable(Person person) {
        this.person = person;
    }

    @Override
    public void run() {
        this.person.say();
    }
}

class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public synchronized void say() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (name.equals("xiaoming"))
            Thread.currentThread().suspend();
        else
            System.out.println("name: " + this.name + " age:" + age);
    }
}

当把name改成xiaoming后第二个线程就一直占有资源,线程3进不去。

使用suspend与resume方法时使用不当会造成公共同步对象的独占。


使用suspend与resume方法时会造成数据不同步。

yield方法的作用是放弃当前CPU资源,但放弃时间不确定

public class TestThread {
    public static void main(String[] args) {
       Thread thread=new Thread(new MyRunnable());
       thread.start();


    }
}

class MyRunnable implements Runnable {

    @Override
    public void run() {
        long start=System.currentTimeMillis();
        for (int i=0;i<1000000000;i++);
        Thread.yield();
        long end=System.currentTimeMillis();
        System.out.println(end-start);
    }
}


线程优先级高获取的cpu资源比较多,线程中的优先级具有继承性

public class TestThread {
    public static void main(String[] args) {
        FatherThread fatherThread = new FatherThread();
        SonThread sonThread = new SonThread();
        //优先级具有继承性
        System.out.println("Father Priority:" + fatherThread.getPriority());
        System.out.println("Son Priority:" + sonThread.getPriority());


    }
}

class FatherThread extends Thread {
    @Override
    public void run() {
        System.out.println("Father");
    }
}

class SonThread extends FatherThread {

}

守护线程

以前太了解守护线程是干啥的。现在知道守护线程就是为其他线程服务的等其它线程结束它才会结束。比如垃圾回收线程。

public class TestThread {
    public static void main(String[] args) {
        MyThread thread=new MyThread();
        thread.setDaemon(true);
        thread.start();
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


    }
}

class MyThread extends Thread {
    @Override
    public void run() {
        for (int i=0;i<10;i++){
            try {
                System.out.println(i);
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}


如何停止线程

使用interrupt()与return结合

public class TestThread {
    public static void main(String[] args) {
        MyThread myThread=new MyThread();
        myThread.start();
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        myThread.interrupt();



    }
}

class MyThread extends Thread {
    @Override
    public void run() {
        while (true) {
            if (this.isInterrupted()){
                System.out.println("Stop>>>>>>>>>>>>");
                return;
            }
            else
                System.out.println(System.currentTimeMillis());
        }
    }
}

总结

主要是Java多线程编程核心技术第一章的读后感自己也动手敲了一遍对一些线程基础理解更加深入了。加油加油!如果有一些问题欢迎指出来感谢。

以上是关于线程基础知识的主要内容,如果未能解决你的问题,请参考以下文章

线程基础四 使用Monitor类锁定资源

Java——线程池

newCacheThreadPool()newFixedThreadPool()newScheduledThreadPool()newSingleThreadExecutor()自定义线程池(代码片段

Java线程池详解

Java线程池详解

Java 线程池详解