java高并发编程--01--认识线程与Thread
1.线程简介 线程的生命周期: RUNNABLE:线程对象调用start方法进入此状态,此时才真正的在JVM进程中创建一个线程,线程具备执行的资格,当CPU调度到它就可以执行。 RUNNING:线程正则执行的状态。该状态下可以进行如下切换: BLOCKED:此状态可以进行如下状态切换: TERMINATED:线程生命周期结束。有以下情况进入此状态: 2.线程的Start方法 public synchronized void start(){
if(threadStatus != 0)
throw new IllegalThreadStateException();
group.add(this);
boolean started = false;
try{
start0();
started = true;
}finally{
try{
if(!started){
group.threadStartFailed(this);
}
}catch(Throwable ignore){
}
}
}
其核心是对JNI方法start0()的调用 3.Runnable 接口的引入及策略模式在Thread类中的使用 Runnable接口的职责声明线程的执行单元 //Thread的run方法:
@Override
public void run() {
if (target != null) {
target.run();
}
}
//Thread的target声明:
private Runnable target;
//Thread的target赋值:
public Thread(Runnable target) {
this(null,target,"Thread-" + nextThreadNum(),0);
}
public Thread(ThreadGroup group,Runnable target,String name,long stackSize) {
this(group,name,stackSize,null,true);
}
private Thread(ThreadGroup g,long stackSize,AccessControlContext acc,boolean inheritThreadLocals) {
。。。
this.target = target;
。。。
}
? 4.Thread构造函数 public Thread(Runnable target) { this(null,"Thread-" + nextThreadNum(),0); } private static int threadInitNumber; private static synchronized int nextThreadNum() { return threadInitNumber++; } 建议给线程指定名字,以便维护。 4.2线程父子关系 4.3Thread和ThreadGroup Thread parent = currentThread(); SecurityManager security = System.getSecurityManager(); if (g == null) { if (security != null) { g = security.getThreadGroup(); } if (g == null) { g = parent.getThreadGroup(); } } this.group = g; 4.4jvm内存结构 ? 1)程序计数器 2)java虚拟机栈 3)本地方法栈 4)堆内存 5)方法区 2.5守护线程 ? public class DaemonThreadTest { public static void main(String[] args) throws Exception { //1)线程开始 Thread t = new Thread(() -> { while(true) { try { Thread.sleep(1); } catch (Exception e) { e.printStackTrace(); } } }); //t.setDaemon(true);//2)调用setDaemon()方法将线程设置为守护线程 t.start();//3)启动线程 Thread.sleep(10000); System.out.println("main线程结束"); //4)主线程结束 } } 代码中有两个线程,一个是jvm启动的main线程,一个自己创建的线程。 5 Thread API 5.1 线程sleep 5.2线程yield 5.3线程优先级 public final void setPriority(int newPriority) { ThreadGroup g; checkAccess(); if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) { throw new IllegalArgumentException(); } if((g = getThreadGroup()) != null) { if (newPriority > g.getMaxPriority()) { newPriority = g.getMaxPriority(); } setPriority0(priority = newPriority); } } 由代码可以看出,优先级是是有范围的,取决于线程所在的ThreadGroup 5.4获取线程ID 5.5线程interrupt public static void main(String[] args) throws Exception { Thread t = new Thread(()-> { double d = Double.MIN_VALUE; while(d < Double.MAX_VALUE-1) { d += 0.1; } System.out.println("HA Ha"); }); t.start(); Thread.sleep(1000);//main线程休眠一会,保证线程t获得CPU执行权真正开始执行 System.out.println(t.isInterrupted());//打断前 t.interrupt();//打断 System.out.println(t.isInterrupted());//查看线程t的flag Thread.sleep(1000);//main线程休眠一会,保证线程t获得CPU执行权继续执行 System.out.println(t.isInterrupted());//再次查看线程t的flag } 代码1输出如下: 代码1中,线程t内的while循环调用的方法是不会让线程t出现阻塞的,即非阻塞方法,即非可中断方法,main线程对其调用interrupt方法,为它设置类flag,flag一种存在 代码2: public static void main(String[] args) throws Exception { Thread t = new Thread(()-> { try { TimeUnit.SECONDS.sleep(10); } catch (Exception e) { System.out.println("I‘m interrepted"); } double d = Double.MIN_VALUE; while(d < Double.MAX_VALUE-1) { d += 0.1; } System.out.println("HA Ha"); }); t.start(); Thread.sleep(1000);//main线程休眠一会,保证线程t获得CPU执行权真正开始执行 System.out.println(t.isInterrupted());//打断前 t.interrupt();//打断 System.out.println(t.isInterrupted());//查看线程t的flag Thread.sleep(1000);//main线程休眠一会,保证线程t获得CPU执行权继续执行 System.out.println(t.isInterrupted());//再次查看线程t的flag } 代码2输出如下: 代码2中,线程t先是休眠10秒,休眠为阻塞方法,为可中断方法,在这段时间内,main线程调用它的interrupt方法,调用前查看标志,flag为false,调用后立即查看标志,flag为ture,等一会,待t线程继续执行抛出异常后,再次查看线程t的flag,flag为false,说明线程flag被清除类,且应是抛出异常时清除的。 2)isInterrupted 3)interrupted public static void main(String[] args) throws Exception { Thread t = new Thread(()-> { while(true) { //因为判断的是当前线程,只能将判断方法写在线程t的run方法范围内 System.out.println(Thread.interrupted()); } }); t.setDaemon(true); t.start(); Thread.sleep(10); t.interrupt(); Thread.sleep(1); t.interrupt(); Thread.sleep(1); } 为了避免抛出异常时清除标识的影响,t中没有用sleep,因此会有很多输出 4)注意事项 public boolean isInterrupted() { return isInterrupted(false); } public static boolean interrupted() { return currentThread().isInterrupted(true); } private native boolean isInterrupted(boolean ClearInterrupted); JNI方法isInterrupted的ClearInterrupted参数用来控制是否擦除interrupt标识,两个调用分别传入不同参数 一个线程如果设置了interrupt标识,那么接下来执行可打断方法时会被立即打断,如sleep方法,验证代码如下: public static void main(String[] args) throws Exception { SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SS"); System.out.println("测试开始:"+sdf.format(new Date())); Thread t = new Thread(()-> { try { System.out.println("初次打断:"+sdf.format(new Date())); Thread.currentThread().interrupt(); TimeUnit.MINUTES.sleep(3); } catch (InterruptedException e) { System.out.println("休眠打断:"+sdf.format(new Date())); } }); System.out.println("线程启动:"+sdf.format(new Date())); t.start(); TimeUnit.MINUTES.sleep(1); System.out.println("再次打断:"+sdf.format(new Date())); t.interrupt(); } 上面代码初始设置打断只能在t的run方法内,因为start前线程t并不真正存在 5.6线程的join import java.util.List; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import java.util.stream.IntStream; public class ThreadJoin { public static void main(String[] args) { //1 定义两个线程,放到threads中 List<Thread> threads = IntStream.range(1,3).mapToObj(ThreadJoin::create).collect(Collectors.toList()); //2启动两个线程 threads.forEach(Thread :: start); //3执行两个线程的join threads.forEach(t -> { try { System.out.println(t.getName() + ",join"); t.join(); } catch (InterruptedException e) { e.printStackTrace(); } }); //4main线程自己的输出 for(int i = 0;i < 5;i ++) { System.out.println(Thread.currentThread().getName() + ",#" + i); shortSleep(); } } //构造一个简单线程,每一个线程只是简单的输出和休眠 private static Thread create(int seq) { return new Thread(()->{ for(int i = 0;i < 5;i ++) { System.out.println(Thread.currentThread().getName() + ",#" + i); shortSleep(); } },"Thread=="+seq); } private static void shortSleep() { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } } 结果: 由上面的输出可以看出:1)join方法可以使当前线程永远等待下去,直到期间被另外的线程中断或者join的线程执行结束或者join指定的时间结束。2)一个线程同一段时间只可以被一个线程join,因为Thread.join()这段代码要在被join的线程中执行,而执行完这一句被join的线程就阻塞类,后面的join语句必须等前面的join结束后才能被执行到 6关闭线程6.1正常关闭1)线程结束生命周期2)捕获中断信号关闭:循环执行任务,循环中调用isInterrupted方法检查中断标志,若中断结束循环3)使用volatile开个控制:循环执行任务,循环中检查volatile变量,volatile变量发生合适改变结束循环6.2异常突出线程的执行单元中适当地方抛出运行时异常结束当前线程 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |