Java Thread 的一些认识:
Java是抢占式线程,一个线程就是进程中单一的顺序控制流,单个进程可以拥有多个并发任务,其底层是切分CPU时间,多线程和多任务往往是使用多处理器系统的最合理方式
进程可以看作一个程序或者一个应用;线程是进程中执行的一个任务,多个线程可以共享资源
一个Java 应用从main 方法开始运行,main 运行在一个线程内,也被称为 “主线程”,Runnable也可以理解为Task (任务)
JVM启动后,会创建一些守护线程来进行自身的常规管理(垃圾回收,终结处理),以及一个运行main函数的主线程
随着硬件水平的提高,多线程能使系统的运行效率得到大幅度的提高,同时异步操作也增加复杂度和各种并发问题
■ 线程 VS 进程
在一个已有进程中创建一个新线程比创建一个新进程快的多
终止一个线程比终止一个进程快的多
同一个进程内线程间切换比进程间切换更快
线程提供了不同的执行程序间通信的效率,同一个进程中的线程共享同一进程内存和文件,无序调用内核就可以互相通信,而进程间通信必须通过内核
■ 同步和异步
同步方法一旦开始,调用者必须等到方法调用返回之后,才能继续后续行为
无先后顺序,一旦开始,方法调用便立即返回,调用者就可以继续后续行为,一般为另一个线程执行
■ 阻塞和非阻塞
当一个线程占用临界区资源,其他线程也想要使用该资源就必须等待,等待会导致线程的挂起,也就是阻塞(线程变成阻塞状态)。
此时若占用资源的线程一直不愿意释放资源,那么其他所有阻塞在该临界区的线程都会被挂起,变成阻塞状态,不能正常工作,直到占用线程释放资源
非阻塞强调没有一个线程可以妨碍其他线程执行,所有线程都会尝试去做下一步工作
■ 临界资源与临界区
一般指的是公共共享资源,即可以被多个线程共享使用。但同一时间只能由一个线程去访问和操作临界区的资源,一旦临界区资源被一个线程占用,其他线程也想要使用该资源就必须等待,
就好比好多人想上大号,但只有一个坑,一个人占了坑,其他人就得排队等待喽
临界区可以认为是一段代码,线程会在该端代码中访问共享资源,因此临界区的界定标准就是是否访问共享(临界)资源(有点类似形成闭包的概念);一次只允许有一个程序(进程/线程)在该临界区中
■ 类定义
public class Thread implements Runnable {
private static native void registerNatives();
static {
registerNatives();
}
■ 构造器
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
public Thread(ThreadGroup group, Runnable target) {
init(group, target, "Thread-" + nextThreadNum(), 0);
}
public Thread(String name) {
init(null, null, name, 0);
}
public Thread(ThreadGroup group, String name) {
init(group, null, name, 0);
}
public Thread(Runnable target, String name) {
init(null, target, name, 0);
}
public Thread(ThreadGroup group, Runnable target, String name) {
init(group, target, name, 0);
}
public Thread(ThreadGroup group, Runnable target, String name,long stackSize) {
init(group, target, name, stackSize);
}
■ 重要变量
//线程名,用char来保存(String底层实现就是char)
private char name[];
//线程优先级
private int priority;
//不明觉厉
private Thread threadQ;
//不明觉厉
private long eetop;
private boolean single_step;
private boolean daemon = false;
private boolean stillborn = false;
private Runnable target;
private ThreadGroup group;
private ClassLoader contextClassLoader;
private AccessControlContext inheritedAccessControlContext;
private static int threadInitNumber;
ThreadLocal.ThreadLocalMap threadLocals = null;
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
private long stackSize;
private long nativeParkEventPointer;
private long tid;
private static long threadSeqNumber;
private volatile int threadStatus = 0;
volatile Object parkBlocker;
private volatile Interruptible blocker;
//阻塞器锁,主要用于处理阻塞情况
private final Object blockerLock = new Object();
public final static int MIN_PRIORITY = 1;
public final static int NORM_PRIORITY = 5;
public final static int MAX_PRIORITY = 10;
private static final StackTraceElement[] EMPTY_STACK_TRACE = new StackTraceElement[0];
private static final RuntimePermission SUBCLASS_IMPLEMENTATION_PERMISSION =
new RuntimePermission("enableContextClassLoaderOverride");
// null unless explicitly set 线程异常处理器,只对当前线程有效
private volatile UncaughtExceptionHandler uncaughtExceptionHandler;
// null unless explicitly set 默认线程异常处理器,对所有线程有效
private static volatile UncaughtExceptionHandler defaultUncaughtExceptionHandler;
■ 本地方法
private static native void registerNatives();
static {
registerNatives();
}
public static native void yield();
public static native void sleep(long millis) throws InterruptedException;
public final native boolean isAlive();
private native boolean isInterrupted(boolean ClearInterrupted);
public static native Thread currentThread();
public static native boolean holdsLock(Object obj);
private native void start0();
private native void setPriority0(int newPriority);
private native void stop0(Object o);
private native void suspend0();
private native void resume0();
private native void interrupt0();
private native void setNativeName(String name);
■ 线程初始化
private void init(ThreadGroup g, Runnable target, String name,long stackSize) {
if (name == null) {
throw new NullPointerException("name cannot be null");
}
//返回当前线程,即创建该hread的线程 currentThread是个本地方法
Thread parent = currentThread();
//安全管理器根据Java安全策略文件决定将哪组权限授予类
//如果想让应用使用安全管理器和安全策略,可在启动JVM时设定-Djava.security.manager选项
//还可以同时指定安全策略文件
//如果在应用中启用了Java安全管理器,却没有指定安全策略文件,那么Java安全管理器将使用默认的安全策略
//它们是由位于目录$JAVA_HOME/jre/lib/security中的java.policy定义的
SecurityManager security = System.getSecurityManager();
if (g == null) {
if (security != null) {
g = security.getThreadGroup();
}
if (g == null) {
g = parent.getThreadGroup();
}
}
//判断当前运行线程是否有变更其线程组的权限
g.checkAccess();
if (security != null) {
if (isCCLOverridden(getClass())) {
security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
}
}
//新建线程数量计数+1 或者说未就绪线程数+1==> nUnstartedThreads++;
g.addUnstarted();
this.group = g;
this.daemon = parent.isDaemon();//若当前运行线程是守护线程,新建线程也是守护线程
this.priority = parent.getPriority();//默认使用当前运行线程的优先级
this.name = name.toCharArray();
//设置contextClassLoader
if (security == null || isCCLOverridden(parent.getClass()))
this.contextClassLoader = parent.getContextClassLoader();
else
this.contextClassLoader = parent.contextClassLoader;
this.inheritedAccessControlContext = AccessController.getContext();
this.target = target;
setPriority(priority);//若有指定的优先级,使用指定的优先级
if (parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
this.stackSize = stackSize;
tid = nextThreadID();
}
private static synchronized long nextThreadID() {
return ++threadSeqNumber;
}
■ start 方法
public synchronized void start() {
if (threadStatus != 0)
throw new IllegalThreadStateException();
//通知所属线程组该线程已经是就绪状态,因而可以被添加到该线程组中
//同时线程组的未就绪线程数需要-1,对应init中的+1
group.add(this);
boolean started = false;
try {
//调用本地方法,将内存中的线程状态变更为就绪态
//同时JVM会立即调用run方法,获取到CPU之后,线程变成运行态并立即执行run方法
start0();
started = true;//标记为已开启
} finally {
try {
if (!started) {
group.threadStartFailed(this);//如果变更失败,要回滚线程和线程组状态
}
} catch (Throwable ignore) {
//如果start0出错,会被调用栈直接通过
}
}
}
-------------
//start之后会立即调用run方法
Thread t = new Thread( new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
},"roman");
t.start(); //roman
■ run 方法
@Override
public void run() {
if (target != null) {
target.run();
}
}
■ isAlive 方法
public final native boolean isAlive();
✺ 线程运行 : 模拟电梯运行类
public class LiftOff implements Runnable {
private int countDown = 10; //电梯阶层
// private static int taskCount = 0;
// private final int id = taskCount++;
public LiftOff(){
}
// syn countDown
private synchronized int getCountDown(){
--countDown;
return countDown;
}
// 获取电梯状态
public String status() {
return Thread.currentThread().toString()+ "("+
(countDown > 0? countDown: "Liftoff!") + "),";
}
@Override
public void run(){
while (getCountDown() >0){
System.out.println(status());
Thread.yield();
}
}
public static void main(String[] args) {
// thread's start()
Thread thread = new Thread(new LiftOff());
thread.start(); // 调用 run()
System.out.println("================Waiting for LiftOff...===========================");
}
}
线程都会有自己的名字
获取线程对象的方法: Thread.currentThread()
目标 run() 结束后线程完成
JVM线程调度程序决定实际运行哪个处于可运行状态的线程
使用线程池执行处理任务
线程状态流程图:
■ sleep 方法
public static void sleep(long millis, int nanos) throws InterruptedException {
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException("nanosecond timeout value out of range");
}
//换算用
if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
millis++;
}
sleep(millis);
}
public static native void sleep(long millis) throws InterruptedException;
■ yield 方法
public static native void yield();
■ interrupt 方法
public void interrupt() {
if (this != Thread.currentThread())
checkAccess();
synchronized (blockerLock) {
Interruptible b = blocker;
if (b != null) {
// Just to set the interrupt flag
// 调用interrupt方法仅仅是在当前线程中打了一个停止的标记,并不是真的停止线程!
interrupt0();
b.interrupt(this);
return;
}
}
interrupt0();
}
■ Daemon
分类:在JAVA中分成两种线程:用户线程和守护线程
特性:当进程中不存在非守护线程时,则全部的守护线程会自动化销毁
应用: JVM在启动后会生成一系列守护线程,最有名的当属GC(垃圾回收器)
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("守护线程运行了");
for (int i = 0; i < 500000;i++){
System.out.println("守护线程计数:" + i);
}
}
}, "kira");
t2.setDaemon(true);
t2.start();
Thread.sleep(500);
-------------
//输出:
......
守护线程计数:113755
守护线程计数:113756
守护线程计数:113757
守护线程计数:113758
//结束打印:会发现守护线程并没有打印500000次,因为主线程已经结束运行了
■ wait 和 notify 机制
wait()使线程停止运行,notify()使停止的线程继续运行
使用wait()、notify()、notifyAll()需要先对调用对象加锁,即只能在同步方法或同步块中调用这些方法
调用wait()方法后,线程状态由RUNNING变成WAITING,并将当前线程放入对象的等待队列中
调用notify()或notifyAll()方法之后,等待线程不会从wait()返回,需要notify()方法所在同步块代码执行完毕而释放锁之后,等待线程才可以获取到该对象锁并从wait()返回
notify()方法将随机选择一个等待线程从等待队列中移到同步队列中;notifyAll()方法会将等待队列中的所有等待线线程全部移到同步队列中,被移动线程状态由WAITING变成BLOCKED
// wait/notify 简单实例
public class NumberPrint implements Runnable {
private int number;
public byte[] res;
public static int count = 5;
public NumberPrint(int number, byte a[]){
this.number = number;
res = a;
}
@Override
public void run() {
synchronized (res){
while (count-- > 0){
try {
res.notify(); //唤醒等待res资源的线程,把锁交给线程(该同步锁执行完毕自动释放锁)
System.out.println(" " + number);
res.wait(); //释放CPU控制权,释放res的锁,本线程阻塞,等待被唤醒
System.out.println("----------线程"+Thread.currentThread().getName() + "获得锁,wait()后的代码继续运行:"+ number);
} catch (InterruptedException e) {
e.printStackTrace();
}
} //end of while
return;
} //syn
}
public static void main(String[] args) {
final byte[] a = {0}; //以该对象为共享资源
new Thread(new NumberPrint(1,a),"1").start();
new Thread(new NumberPrint(2,a),"2").start();
}
}
*****各位看客,由于对线程的调度机制还理解比较浅,所以本文会持续更新…… ********
以上这篇浅谈多线程_让程序更高效的运行就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持考高分网。



