Java基础-concurrent (3)

在Java中,每个应用程序最少有一个执行线程,运行程序时,JVM负责调用main()方法的执行线程。
当全部的非守护线程执行结束时,Java程序才算结束。从输出中也可以看到,主程序输出main thread end后,其他程序还是继续执行,直到执行结束。
需要注意的是,如果某个线程调用System.exit()指示终结程序,那么全部的线程都会结束执行。

线程中断、睡眠、设置优先级

下面的示例中,NumberGenerator中首先创建numberGenetorThread线程,并设置优先级,启动线程后,一直循环运行,打印出number的值,直到5毫秒后主线程调用interrupt()方法让其中断,numberGenetorThread线程其跳出while循环。首次调用方法isInterrupted()返回值为true,表示线程已中断。
需要注意的是,interrupt()方法测试当前线程是否已经中断,线程的中断状态也由该方法清除。换句话说,如果连续两次调用该方法,则第二次调用将返回 false。大家可以打开下面的注释去测试。

package com.molyeo.java.concurrent; /** * Created by zhangkh on 2018/8/23. */ public class ThreadTest2 { public static void main(String[] args) throws InterruptedException { Thread numberGenetorThread = new NumberGenerator(0); numberGenetorThread.setPriority(Thread.MAX_PRIORITY); numberGenetorThread.start(); Thread.sleep(5); numberGenetorThread.interrupt(); System.out.println("first interrupt,isInterrupted=" + numberGenetorThread.isInterrupted()); // Thread.sleep(5); // numberGenetorThread.interrupt(); // System.out.println("second interrupt,isInterrupted=" + numberGenetorThread.isInterrupted()); } } class NumberGenerator extends Thread { private int number; public NumberGenerator(int number) { this.number = number; } @Override public void run() { while (!isInterrupted()) { System.out.println("number is " + number); number++; } System.out.println("NumberGenerator thread,isInterrupted= " + this.isInterrupted()); } }

程序部分输出如下:

number is 96 number is 97 NumberGenerator thread,isInterrupted= true first interrupt,isInterrupted=true ThreadLocal

定义和作用
ThreadLocal称线程本地变量,并不是为了解决共享对象的多线程访问的问题的,因为如果ThreadLocal.set()放进去的本来就是多线程共享的同一个对象的话,线程通过ThreadLocal.get()方法得到的还是共享对象本身,依旧存在并发访问的问题。其是每个线程所单独持有的,主要是提供了保持对象的方法和避免参数传递,以方便对象的访问。

每个线程中都有一个自己的ThreadLocalMap类对象,可以将线程自己的对象保持到其中,各管各的,线程可以正确的访问到自己的对象。

将一个共用的ThreadLocal静态实例作为key,将不同对象的引用保存到不同线程的ThreadLocalMap中,然后在线程执行的各处通过这个静态ThreadLocal实例的get()方法取得自己线程保存的那个对象,避免了将这个对象作为参数传递的麻烦。

程序运行时,每个线程都保持对其线程局部变量副本的隐式引用,只要线程是活动的并且 ThreadLocal 实例是可访问的;在线程消失之后,其线程局部实例的所有副本都会被垃圾回收(除非存在对这些副本的其他引用)。

使用示例
如下我们创建ThreadLocal的实例stringLocal,分别在主线程和子线程中设置其值为当前线程名字。查看输出的结果可以看到线程间彼此不干扰,各自输出自己设置的值。

package com.molyeo.java.concurrent; /** * Created by zhangkh on 2018/8/24. */ public class ThreadLocalDemo { public static void main(String[] args) throws InterruptedException { ThreadLocal<String> stringLocal = new ThreadLocal<String>(); stringLocal.set(Thread.currentThread().getName()); System.out.println(String.format("threadName=%10s,threadLocal valaue=%10s",Thread.currentThread().getName(),stringLocal.get()) ); Thread thread1 = new Thread() { public void run() { stringLocal.set(Thread.currentThread().getName()); System.out.println(String.format("threadName=%10s,threadLocal valaue=%10s",Thread.currentThread().getName(),stringLocal.get()) ); } }; thread1.start(); thread1.join(); System.out.println(String.format("threadName=%10s,threadLocal valaue=%10s",Thread.currentThread().getName(),stringLocal.get()) ); } }

程序输出如下:

threadName= main,threadLocal valaue= main threadName= Thread-0,threadLocal valaue= Thread-0 threadName= main,threadLocal valaue= main

源码实现
ThreadLocal有3个成员变量

private final int threadLocalHashCode = nextHashCode(); private static AtomicInteger nextHashCode = new AtomicInteger(); private static final int HASH_INCREMENT = 0x61c88647; private static int nextHashCode() { return nextHashCode.getAndAdd(HASH_INCREMENT); }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wppgsp.html