java 线程 总结

1.前言

(1)线程的上一级是进程,进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。
(2)线程与进程相似,但线程是一个比进程更小的执行单位,也被称为轻量级进程。一个进程在其执行的过程中可以产生多个线程。
(3)多线程就是多个线程同时运行或交替运行。
(4)提倡多线程而不是多进程 的原因是 线程间的切换和调度的成本远远小于进程。
(5)自定义线程可以继承Thread类 ,或者 实现Runnable接口 。
(6)多进程共享数据导致脏数据,可以使用同步锁 synchronized 解决。
(7)使用 interrupt() 和 return 配合 停止线程。
(8)不是优先级低的线程就一定在优先级高的线程后面运行,而是运行的机率会低一些,,反之亦然。
(9)线程分为用户线程和守护线程 ,当 用户线程 结束后,守护线程跟着结束 ,对于自定义线程可使用方法 setDaemon(true); 设置该线程为守护线程 。
  常见的 守护线程是 垃圾回收线程
(10)开启线程的方式一共三种:Thread类、Runnable接口、callable接口

2.自定义线程

package com.example.javabaisc.myThread;

import org.junit.jupiter.api.Test;

public class T1 {

    @Test
    public void t1(){
        //调用方法一
//        Mythread m = new Mythread();
//        m.start();


        //调用方法二
        MyRunnable mr = new MyRunnable();
        Thread thread=new Thread(mr);
        thread.start();
        System.out.println("结束");


    }


}

//方法一:
class Mythread extends Thread {
    @Override
    public void run(){
        super.run();
        System.out.println("我的线程");

    }

}

//方法二:
class MyRunnable implements Runnable{

    @Override
    public void run() {
        System.out.println("使用接口实现我的线程");
    }
}
View Code

3.多个线程之间不共享变量线程安全的情况

每个线程都有自己的实例变量count ,互不影响
package com.example.javabaisc.myThread;

import org.junit.jupiter.api.Test;

/**
 * 多个线程之间不共享变量线程安全的情况
 */
public class T2 {

    @Test
    public void t2(){
        MyThread2 m1 = new MyThread2("1");
        MyThread2 m2 = new MyThread2("2");
        MyThread2 m3 = new MyThread2("3");
        m1.start();
        m2.start();
        m3.start();

    }

}

class MyThread2 extends Thread {
    private int count = 5;

    MyThread2(String name) {
//        super();
        //给父类的name属性赋值
        this.setName(name);
    }

    //每次new MyThread2只会执行一次run();
    @Override
    public void run() {
        super.run();
        while (count>0){
            System.out.println("由 线程 " + MyThread2.currentThread().getName() + " 计算,剩余count=" + count);
            count--;
        }
    }
}

/*
由 线程 1 计算,剩余count=5
由 线程 1 计算,剩余count=4
由 线程 1 计算,剩余count=3
由 线程 1 计算,剩余count=2
由 线程 1 计算,剩余count=1
由 线程 3 计算,剩余count=5
由 线程 2 计算,剩余count=5
由 线程 3 计算,剩余count=4
由 线程 3 计算,剩余count=3
由 线程 3 计算,剩余count=2
由 线程 3 计算,剩余count=1
由 线程 2 计算,剩余count=4
由 线程 2 计算,剩余count=3
由 线程 2 计算,剩余count=2
由 线程 2 计算,剩余count=1
 */

/*
每个线程都有自己的实例变量count ,互不影响
 */
View Code

4.共享数据的情况 [使用 同步锁 可解决脏数据问题]

package com.example.javabaisc.myThread;

import org.junit.jupiter.api.Test;

/**
 * 共享数据的情况 [使用 同步锁 可解决脏数据问题]
 */
public class T3 {
    @Test
    public void t3() {
        MyThread3 myThread3 = new MyThread3();
        //参数分别是 自定义线程 ,线程名字
        Thread m1 = new Thread(myThread3, "1");
        Thread m2 = new Thread(myThread3, "2");
        Thread m3 = new Thread(myThread3, "3");
        Thread m4 = new Thread(myThread3, "4");
        Thread m5 = new Thread(myThread3, "5");
        m1.start();
        m2.start();
        m3.start();
        m4.start();
        m5.start();

    }
}

//class  MyThread3 extends Thread {
//    //公共数据
//    private int count = 5;
//    //每次new MyThread3只会执行一次run();
//    @Override
//    public  void run() {
//        super.run();
//        int yu = count--;
//        System.out.println("由 线程 " + MyThread3.currentThread().getName() + " 计算,剩余count=" + yu);
//
//    }
//}

/*
由 线程 3 计算,剩余count=2
由 线程 5 计算,剩余count=3
由 线程 1 计算,剩余count=5
由 线程 4 计算,剩余count=1
由 线程 2 计算,剩余count=4
 */

/*
本应该剩余count是依次递减的 ,可是显示是乱数据,
因为在大多数jvm中,count–-的操作分为如下三步:
取得原有count值
计算 -1 的结果
进行赋值
并发线程获取count的值显然是无法避免脏数据

 */

//使用锁 synchronized,即可解决线程脏数据
class  MyThread3 extends Thread {
    //公共数据
    private int count = 5;
    //每次new MyThread3只会执行一次run();
    //添加了同步锁 synchronized
    @Override
    public synchronized void run() {
        super.run();
        int yu = count--;
        System.out.println("由 线程 " + MyThread3.currentThread().getName() + " 计算,剩余count=" + yu);

    }
}
/*
由 线程 1 计算,剩余count=5
由 线程 5 计算,剩余count=4
由 线程 4 计算,剩余count=3
由 线程 3 计算,剩余count=2
由 线程 2 计算,剩余count=1
 */
View Code

5.使用 interrupt() 和 return 配合 停止线程

package com.example.javabaisc.myThread;

import org.junit.jupiter.api.Test;

/**
 * 使用 interrupt() 和 return 配合 停止线程
 */

public class T4 {


    @Test
    public void t() throws InterruptedException {
        MyThread4 m = new MyThread4();
        m.start();
        //主线程休眠0.01秒后执行
        Thread.sleep(10);
        m.interrupt();
        Thread.sleep(1000);
        System.out.println("停了么?");

    }

}

class MyThread4 extends Thread {

    //每次new MyThread4只会执行一次run();
    @Override
    public  void run() {
        super.run();
        int i = 0;
        while (true) {
            //判断该线程是否被执行了interrupt()
            if (this.isInterrupted()) {
                System.out.println("线程被停止");
                return;
            }
            System.out.println(i++);
        }

    }
}
View Code

打印结果:

 

 

 6.线程优先级对比

setPriority不一定起作用的,在不同的操作系统不同的jvm上,效果也可能不同
数字越大优先级越高,但不是优先级低就一定在优先级高的线程后面运行,而是运行的机率会低一些,,反之亦然。
package com.example.javabaisc.myThread;

import org.junit.jupiter.api.Test;

/**
 * 线程优先级对比
 * setPriority不一定起作用的,在不同的操作系统不同的jvm上,效果也可能不同
 * 数字越大优先级越高,但不是优先级低就一定在优先级高的线程后面运行,而是运行的机率会低一些,,反之亦然。
 *
 */
public class T5 {
    @Test
    public void t() {
        MyThread5 a = new MyThread5("A");
        MyThread5 b = new MyThread5("B");
//        a.setPriority(10);
//        b.setPriority(1);
        a.setPriority(1);
        b.setPriority(10);
        a.start();
        b.start();

    }

}

class MyThread5 extends Thread {

    MyThread5(String name) {
        super();
        this.setName(name);
    }

    @Override
    public  void run() {
        super.run();
        System.out.println("我是线程:" + Thread.currentThread().getName());
    }
}
View Code

 7.守护线程 ,当 用户线程 结束后,守护线程跟着结束 

注意:

不可使用@Test测试 ,否则所有线程都会随着用户线程结束而结束,看不到非守护线程运行效果
package com.example.javabaisc.myThread;

import org.junit.jupiter.api.Test;

/**
 * 守护线程 ,当 用户线程 结束后,守护线程跟着结束
 *
 * 不可使用@Test测试 ,否则所有线程都会随着用户线程结束而结束,看不到非守护线程运行效果
 *
 *
 */
public class T6 {

public static void main(String[] args) throws InterruptedException {
        MyThread6 a = new MyThread6();
        //设置该线程为守护线程
        a.setDaemon(true);
        a.start();
        Thread.sleep(1000);
        System.out.println("用户线程结束,退出,守护线程也跟着退出");


    }
}


class MyThread6 extends Thread {
    private int i = 0;

    @Override
    public void run() {
        while (true) {
            System.out.println(i++);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }


        }

    }
}
View Code

 

不设为守护线程的打印结果

 

 设为守护线程的打印结果

 

 

posted @ 2020-06-12 16:02  岑惜  阅读(172)  评论(0编辑  收藏  举报