线程基础知识

线程启动方式

  • Thread类
  • Runable接口
  • Callable接口(有返回值)
    private static class Test implements Callable<String> {
        @Override
        public String call() throws Exception {
            return "Callable";
        }
    }
    private static class Test2 extends Thread {
        @Override
        public void run() {
            System.out.println("thread");
        }
    }
    private static class Test3 implements Runnable {

        @Override
        public void run() {
            System.out.println("Runnable");
        }
    }
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // new thread
        new Test2().start();
        // runable
        new Thread(new Test3()).start();
        // Callable
        FutureTask<String> futureTask = new FutureTask<>(new Test());
        new Thread(futureTask).start();
        String res = futureTask.get();
        System.out.println("返回值" + res);
    }

如果直接调用run方法,那么它跟调用一个普通方法是一模一样的,并不会新起一个线程

停止线程

  • 等待线程执行结束,或者抛出异常
  • stop()。不建议使用,已废弃会强制终结线程,无法保证线程的正常释放,这会导致对象处于不一致的状态。例如某个流程有两步操作,但是执行完第一步,就stop,第二部没有执行,就会导致对象被破坏
  • suspend()。不建议使用,已废弃。调用suspend()的时候,目标线程会停下来,但却仍然持有在这之前获得的锁定。此时,其他任何线程都不能访问锁定的资源,除非被”挂起”的线程恢复运行。对任何线程来说,如果它们想恢复目标线程,同时又试图使用任何一个锁定的资源,就会造成死锁。
  • interrupt()、isInterrupted()。 interrupt()发出中断线程信号,它仅仅是发出中断的信号,而是否中断线程需要线程自己操作;isInterrupted()判断线程是否处于中断状态
  • 使用成员变量做状态标志。不太推荐,因为这种方法必须在阻塞线程运行完之后才会判断状态,可以配合interrupt使用。
    static class myThread extends Thread {
        @Override
        public void run() {
            String threadName = Thread.currentThread().getName();
            // 必须在线程里去处理线程中断,否则线程不会中断
            while (!isInterrupted()) {
                System.out.println(threadName + "is running : " + isInterrupted());
            }
            System.out.println(threadName + "is stop:" + isInterrupted());
        }
    }
    static class myRun implements Runnable {
        @Override
        public void run() {
            String threadName = Thread.currentThread().getName();
            // 必须在线程里去处理线程中断,否则线程不会中断
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println(threadName + "is running : " + Thread.currentThread().isInterrupted());
            }
            System.out.println(threadName + "is stop:" + Thread.currentThread().isInterrupted());
        }
    }
    public static void main(String[] args) throws InterruptedException {
        myThread myThread = new myThread();
        myThread.setName("endThread");
        myThread.start();
        Thread.sleep(2000);
        myThread.interrupt();
        // run方式
        Thread myRun = new Thread(new myRun());
        myRun.start();
        Thread.sleep(2000);
        myRun.interrupt();
    }

interrupt()注意点

    static class MyThread extends Thread {
        @Override
        public void run() {
            String threadName = Thread.currentThread().getName();
            // 必须在线程里去处理线程中断,否则线程不会中断
            while (!isInterrupted()) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    // 方法抛出InterruptedException后,中断状态会复位,线程不会停止
                    // 所以需要再次调用interrupt()
                    interrupt();
                    System.out.println(threadName + "in Exception : " + isInterrupted());
                }
                System.out.println(threadName + "is running : " + isInterrupted());
            }
            System.out.println(threadName + "is stop:" + isInterrupted());
        }
    }

优先级

    优先级为1-10,缺省为5。数字越高,优先级越高,一般较少使用,因为执行顺序并不可靠。

myThread.setPriority(6);

守护线程

    守护线程是指为其他线程服务的线程。主线程退出,守护线程一定会退出。重要的特性是后台运行。

myThread.setDaemon(true);

线程间的共享

  • synchronized锁

  • volatile

它适合一写多读,因为它能保证变量的可见性,https://blog.csdn.net/zgsxhdzxl/article/details/88095284 可以先看一下jvm的内存模型。

1、保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。volatile修饰的变量,它会认为其缓存是无效的,所以每次修改都会立即写入主存,读数据也会每次都从主存中获取最新值。但是它非原子性,不保证线程安全。

public class VolatileTest {
    static class Test extends Thread {
        private volatile int a = 0;

        @Override
        public void run() {
            String name = Thread.currentThread().getName();
            a++;
            System.out.println("线程" + name + "的值为" + a);
            a++;
            System.out.println("线程" + name + "的值为" + a);
        }
    }
    public static void main(String[] args) {
// 可以看到a的值并没有递增, 没有保证安全
        Test test = new Test();
        Test test2 = new Test();
        Test test3 = new Test();
        Test test4 = new Test();
        test.start();
        test2.start();
        test3.start();
        test4.start();
    }
}

2、禁止进行指令重排序..

  • threadLocal

https://blog.csdn.net/zgsxhdzxl/article/details/104710702

 

线程间的协作

  • wait()和notify()、notifyAll()

  wait()的作用是让当前线程进入等待状态,尽量使用notifyAll(),notify()只会随机唤醒一个线程。

  • Join()

Join交出当前线程的执行权,等待其他线程执行完之后再执行。

public static void main(String[] args) throws InterruptedException {
    Thread a = new Thread(){
        @Override
        public void run() {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    };
    a.start();
    a.join();
    System.out.println("所有子线程执行完成");
}

休眠sleep

Thread.sleep(1000)

TimeUnit.SECONDS.sleep(10)

sleep是Thread类的一个方法,wait是Object类的一个方法。
sleep不会释放资源,wait会释放掉资源

yield也不会释放锁,但是他有可能又继续执行。而spleep是睡眠时间结束后,才有可能继续执行

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值