【java总结】多线程(基础篇)(5篇)

时间:2019-05-12 16:43:31下载本文作者:会员上传
简介:写写帮文库小编为你整理了多篇相关的《【java总结】多线程(基础篇)》,但愿对你工作学习有帮助,当然你在写写帮文库还可以找到更多《【java总结】多线程(基础篇)》。

第一篇:【java总结】多线程(基础篇)

【java总结】多线程(基础篇)

Java的线程分为5种状态:创建、就绪、运行、阻塞和死亡。

创建:

在java种创建线程的方式有两种,一种是通过继承Thread类并且重写run方法,run方法中执行的代码便是线程执行的代码。另一种是通过实现Runnable接口,并将该接口实例传入一个Thread实例。通过对Thread的引用调用start()方法,即可让线程进入就绪状态。如果直接调用run方法,并不会生成线程,而是在当前线程中把run()当做一个普通方法执行。[java] view plain copy public class Thread1 extends Thread{

/*

* 实现线程的方法一:通过继承Thread并覆盖run()方法来实现多线程。

*/

@Override

public void run(){

System.out.println(Thread.currentThread().getName()+“线程开始!”);

for(int i=0;i<10;i++){

System.out.println(Thread.currentThread().getName()+“ ”+i);

try{

sleep((int)Math.random()*10);

}catch(InterruptedException e){

e.printStackTrace();

}

}

System.out.println(Thread.currentThread().getName()+“线程结束!”);

}

}

[java] view plain copy public class Thread2 implements Runnable{

/*

* 实现线程的方法二:通过实现Runnable接口来实现多线程

* 实现Runnable接口比继承Thread类所具有的优势:

* 1):适合多个相同的程序代码的线程去处理同一个资源

* 2):可以避免java中的单继承的限制

* 3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立

*/

@Override

public void run(){

System.out.println(Thread.currentThread().getName()+“线程开始!”);

for(iwww.xiexiebang.comnt i=0;i<10;i++){

System.out.println(Thread.currentThread().getName()+“ ”+i);

try{

Thread.sleep((int)Math.random()*10);

}catch(InterruptedException e){

e.printStackTrace();

}

}

System.out.println(Thread.currentThread().getName()+“线程结束!”);

}

}

就绪:

处于就绪状态的线程随时可以被JVM的线程调度器调度,进入运行状态。对于处于就绪状态的线程,我们并不能对他们被调度的顺序进行任何估计,也就是说,线程的执行顺序是不可预测的。处于运行状态的线程,通过调用yield()方法,可以返回到就绪状态,然而它有可能瞬间被再次调度。yield()方法把运行机会让给了同等优先级的其他线程。

[java] view plain copy public class ThreadYield extends Thread{

@Override

public void run(){

for(int i = 1;i <= 50;i++){

System.out.println(“" +Thread.currentThread().getName()+ ”-----“ + i);

// 当i==25时,该线程就会把CPU时间让掉,让其他或者自己的线程执行(也就是谁先抢到谁执行)

if(i==25){

this.yield();

}

}

}

}

[java] view plain copy public class ThreadYieldTest {

/*

* Thread.yield():暂停当前正在执行的线程对象,并执行其他线程。

* 该方法让当前线程回到可运行状态,以允许其他具有相同优先级的线程获得运行机会。

* 但是实际中无法保证yield()达到让步目的,因为当前线程有可能被线程调度程序再次选中。

*/

public static void main(String[] args){

ThreadYield thread1=new ThreadYield();

ThreadYield thread2=new ThreadYield();

thread1.start();

thread2.start();

}

}

运行:

处于运行状态的线程随时有可能被线程调度器换下,进入到就绪状态。想要规定线程的顺序,需要调用join方法,对某个线程 的调用join方法,则主线程会阻塞到该线程执行完后再继续执行。或者使用一种叫做锁的机制(下文会提及)。当一个线程完成它run()里面的所有工作时,线程会自动死亡。调用sleep(),线程会进入休眠,并且在一段时间内不会被再度调用。睡眠时间过后,线程才再次进入就绪队列中。

[java] view plain copy public class ThreadJoinTest {

/*

* join是Thread类的一个方法,作用是等待该线程终止。例如对子线程A调用join()方法,* 主线程将等待子线程A终止后才能继续后面的代码。

*/

public static void main(String[] args){

System.out.println(”主线程开始!“);

Thread1 thread1=new Thread1();

Thread1 thread2=new Thread1();

thread1.start();

thread2.start();

try{

thread1.join();

}catch(InterruptedException e){

e.printStackTrace();

}

try{

thread2.join();

}catch(InterruptedException e){

e.printStackTrace();

}

System.out.println(”主线程结束!“);

} }

死亡:

线程因为代码执行完毕而正常结束自身线程,或者因为某些异常而结束线程。

[java] view plain copy public class ThreadInterrupt extends Thread{

/*

* wait()和sleep()都可以通过interrupt()方法 打断线程的暂停状态,从而使线程立刻抛出Interruptedwww.xiexiebang.comt i=0;i<3;i++){

new Thread(new Runnable(){

@Override

public void run(){

ThreadSynchronizedTest x=new ThreadSynchronizedTest();

System.out.println(”value=“+x.getNext());

System.out.println(”value=“+x.getNext2());

System.out.println(”value=“+x.getNext3());

}

}).start();

}

}

}

阻塞:

阻塞跟Obj.wait(),Obj.notify()方法有关。当调用wait方法时,线程释放对象锁,进入阻塞状态,直到其他线程唤醒它。

Obj.wait(),与Obj.notify()必须要与synchronized(Obj)一起使用

Obj.notify()作用:对对象锁的唤醒操作。notify()调用后,并不是马上就释放对象锁的,而 是在相应的synchronized(){}语句块执行结束,自动释放锁后,JVM会在wait()对象锁的线 程中随机选取一线程,赋予其对象锁,唤醒线程,继续执行。

Obj.wait()作用:线程在获取对象锁后,主动释放对象锁,同时本线程休眠,直到有其它线程调用

对象的notify()唤醒该线程,才能继续获取对象锁,并继续执行。下面我们通过一道题目来加深理解。

问题:建立三个线程,A线程打印10次A,B线程打印10次B,C线程打印10次C,要求线程同时运行,交替打印10次ABC。代码如下:

[java] viewww.xiexiebang.comw plain copy public class ThreadPrintABCTest {

/*

* 建立三个线程,A线程打印10次A,B线程打印10次B,C线程打印10次C,要求线程同时运行,交替打印10次ABC。

*

*/

public static void main(String[] args)throws Exception {

Object a = new Object();

Object b = new Object();

Object c = new Object();

ThreadPrintABC pa = new ThreadPrintABC(”A“, c, a);

ThreadPrintABC pb = new ThreadPrintABC(”B“, a, b);

ThreadPrintABC pc = new ThreadPrintABC(”C“, b, c);

new Thread(pa).start();

Thread.sleep(100);//确保按顺序A、B、C执行

new Thread(pb).start();

Thread.sleep(100);

new Thread(pc).start();

Thread.sleep(100);

}

}

[java] view plain copy public class ThreadPrintABC implements Runnable{

private String data;

private Object pre;

private Object self;

public ThreadPrintABC(String data,Object pre,Object self){

this.data=data;

this.pre=pre;

this.self=self;

}

@Override

public void run(){

int count=10;

while(count>0){

synchronized(pre){

synchronized(self){

if(data==”C"){

System.out.println(data);

}else{

System.out.print(data);

}

count--;

self.notify();

}

try{

pre.wait();

}catch(InterruptedException e){

e.printStackTrace();

}

}

}

}

}

死锁:

两个或两个以上的线程在执行过程当中,由于竞争资源或者彼此之间通信而造成的一种阻塞现象。比如,当线程A调用wait()方法等待线程B的唤醒,而线程B同时也调用wait方法等待线程A的唤醒,这时两个线程将陷入僵持状态,永远处在阻塞状态,成为死锁进程,即两个线程永远也不会被执行。

sleep方法与wait方法的区别及细节:

sleep()睡眠时,保持对象锁,仍然占有该锁;而wait()睡眠时,释放对象锁。sleep()使当前线程进入停滞状态(阻塞当前线程),让出CPU的使用、目的是不让当前线程独自霸占该进程所获的CPU资源,以留一定时间给其他线程执行的机会;sleep()是Thread类的Static(静态)的方法;因此他不能改变对象的机锁,所以当在一个Synchronized块中调用Sleep()方法是,线程虽然休眠了,但是对象的锁并木有被释放,其他线程无法访问这个对象(即使睡着也持有对象锁)。在sleep()休眠时间期满后,该线程不一定会立即执行,这是因为其它线程可能正在运行而且没有被调度为放弃执行,除非此线程具有更高的优先级。

wait()方法是Object类里的方法;当一个线程执行到wait()方法时,它就进入到一个和该对象相关的等待池中,同时失去(释放)了对象的机锁(暂时失去锁,wait(long timeout)超时时间到后还需要返还对象锁);其他线程可以访问;

wait()使用notify或者notifyAlll或者指定睡眠时间来唤醒当前等待池中的线程。wiat()必须放在synchronizedblock中,否则扔出”java.lang.IllegalMonitorStateException“异常。

第二篇:Java多线程编程总结

Java多线程编程总结

2007-05-17 11:21:59 标签:java 多线程

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处、作者信息和本声明。否则将追究法律责任。http://lavasoft.blog.51cto.com/62575/27069

Java多线程编程总结

下面是Java线程系列博文的一个编目:

Java线程:概念与原理 Java线程:创建与启动

Java线程:线程栈模型与线程的变量 Java线程:线程状态的转换 Java线程:线程的同步与锁 Java线程:线程的交互 Java线程:线程的调度-休眠 Java线程:线程的调度-优先级 Java线程:线程的调度-让步 Java线程:线程的调度-合并 Java线程:线程的调度-守护线程 Java线程:线程的同步-同步方法 Java线程:线程的同步-同步块

Java线程:并发协作-生产者消费者模型 Java线程:并发协作-死锁 Java线程:volatile关键字 Java线程:新特征-线程池

Java线程:新特征-有返回值的线程 Java线程:新特征-锁(上)Java线程:新特征-锁(下)Java线程:新特征-信号量 Java线程:新特征-阻塞队列 Java线程:新特征-阻塞栈 Java线程:新特征-条件变量 Java线程:新特征-原子量 Java线程:新特征-障碍器 Java线程:大总结

----

下面的内容是很早之前写的,内容不够充实,而且是基于Java1.4的内容,Java5之后,线程并发部分扩展了相当多的内容,因此建议大家看上面的系列文章的内容,与时俱进,跟上Java发展的步伐。----

一、认识多任务、多进程、单线程、多线程 要认识多线程就要从操作系统的原理说起。

以前古老的DOS操作系统(V 6.22)是单任务的,还没有线程的概念,系统在每次只能做一件事情。比如你在copy东西的时候不能rename文件名。为了提高系统的利用效率,采用批处理来批量执行任务。

现在的操作系统都是多任务操作系统,每个运行的任务就是操作系统所做的一件事情,比如你在听歌的同时还在用MSN和好友聊天。听歌和聊天就是两个任务,这个两个任务是“同时”进行的。一个任务一般对应一个进程,也可能包含好几个进程。比如运行的MSN就对应一个MSN的进程,如果你用的是windows系统,你就可以在任务管理器中看到操作系统正在运行的进程信息。

一般来说,当运行一个应用程序的时候,就启动了一个进程,当然有些会启动多个进程。启动进程的时候,操作系统会为进程分配资源,其中最主要的资源是内存空间,因为程序是在内存中运行的。在进程中,有些程序流程块是可以乱序执行的,并且这个代码块可以同时被多次执行。实际上,这样的代码块就是线程体。线程是进程中乱序执行的代码流程。当多个线程同时运行的时候,这样的执行模式成为并发执行。

多线程的目的是为了最大限度的利用CPU资源。

Java编写程序都运行在在Java虚拟机(JVM)中,在JVM的内部,程序的多任务是通过线程来实现的。每用java命令启动一个java应用程序,就会启动一个JVM进程。在同一个JVM进程中,有且只有一个进程,就是它自己。在这个JVM环境中,所有程序代码的运行都是以线程来运行。

一般常见的Java应用程序都是单线程的。比如,用java命令运行一个最简单的HelloWorld的Java应用程序时,就启动了一个JVM进程,JVM找到程序程序的入口点main(),然后运行main()方法,这样就产生了一个线程,这个线程称之为主线程。当main方法结束后,主线程运行完成。JVM进程也随即退出。

对于一个进程中的多个线程来说,多个线程共享进程的内存块,当有新的线程产生的时候,操作系统不分配新的内存,而是让新线程共享原有的进程块的内存。因此,线程间的通信很容易,速度也很快。不同的进程因为处于不同的内存块,因此进程之间的通信相对困难。

实际上,操作的系统的多进程实现了多任务并发执行,程序的多线程实现了进程的并发执行。多任务、多进程、多线程的前提都是要求操作系统提供多任务、多进程、多线程的支持。

在Java程序中,JVM负责线程的调度。线程调度是值按照特定的机制为多个线程分配CPU的使用权。调度的模式有两种:分时调度和抢占式调度。分时调度是所有线程轮流获得CPU使用权,并平均分配每个线程占用CPU的时间;抢占式调度是根据线程的优先级别来获取CPU的使用权。JVM的线程调度模式采用了抢占式模式。

所谓的“并发执行”、“同时”其实都不是真正意义上的“同时”。众所周知,CPU都有个时钟频率,表示每秒中能执行cpu指令的次数。在每个时钟周期内,CPU实际上只能去执行一条(也有可能多条)指令。操作系统将进程线程进行管理,轮流(没有固定的顺序)分配每个进程很短的一段是时间(不一定是均分),然后在每个线程内部,程序代码自己处理该进程内部线程的时间分配,多个线程之间相互的切换去执行,这个切换时间也是非常短的。因此多任务、多进程、多线程都是操作系统给人的一种宏观感受,从微观角度看,程序的运行是异步执行的。

用一句话做总结:虽然操作系统是多线程的,但CPU每一时刻只能做一件事,和人的大脑是一样的,呵呵。

二、Java与多线程

Java语言的多线程需要操作系统的支持。

Java 虚拟机允许应用程序并发地运行多个执行线程。Java语言提供了多线程编程的扩展点,并给出了功能强大的线程控制API。

在Java中,多线程的实现有两种方式: 扩展java.lang.Thread类 实现java.lang.Runnable接口

每个线程都有一个优先级,高优先级线程的执行优先于低优先级线程。每个线程都可以或不可以标记为一个守护程序。当某个线程中运行的代码创建一个新 Thread 对象时,该新线程的初始优先级被设定为创建线程的优先级,并且当且仅当创建线程是守护线程时,新线程才是守护程序。

当 Java 虚拟机启动时,通常都会有单个非守护线程(它通常会调用某个指定类的 main 方法)。Java 虚拟机会继续执行线程,直到下列任一情况出现时为止:

调用了 Runtime 类的 exit 方法,并且安全管理器允许退出操作发生。

非守护线程的所有线程都已停止运行,无论是通过从对 run 方法的调用中返回,还是通过抛出一个传播到 run 方法之外的异常。

三、扩展java.lang.Thread类

/** * File Name: TestMitiThread.java * Created by: IntelliJ IDEA.* Copyright: Copyright(c)2003-2006 * Company: Lavasoft([url]http://lavasoft.blog.51cto.com/[/url])* Author: leizhimin * Modifier: leizhimin * Date Time: 2007-5-17 10:03:12 * Readme: 通过扩展Thread类实现多线程 */ public class TestMitiThread { public static void main(String[] rags){ System.out.println(Thread.currentThread().getName()+ “ 线程运行开始!”);new MitiSay(“A”).start();new MitiSay(“B”).start();System.out.println(Thread.currentThread().getName()+ “ 线程运行结束!”);} }

class MitiSay extends Thread { public MitiSay(String threadName){ super(threadName);}

public void run(){ System.out.println(getName()+ “ 线程运行开始!”);for(int i = 0;i < 10;i++){ System.out.println(i + “ ” + getName());try { sleep((int)Math.random()* 10);} catch(InterruptedException e){ e.printStackTrace();} } System.out.println(getName()+ “ 线程运行结束!”);} }

运行结果:

main 线程运行开始!main 线程运行结束!A 线程运行开始!0 A 1 A B 线程运行开始!2 A 0 B 3 A 4 A 1 B 5 A 6 A 7 A 8 A 9 A A 线程运行结束!2 B 3 B 4 B 5 B 6 B 7 B 8 B 9 B B 线程运行结束!说明:

程序启动运行main时候,java虚拟机启动一个进程,主线程main在main()调用时候被创建。随着调用MitiSay的两个对象的start方法,另外两个线程也启动了,这样,整个应用就在多线程下运行。

在一个方法中调用Thread.currentThread().getName()方法,可以获取当前线程的名字。在mian方法中调用该方法,获取的是主线程的名字。

注意:start()方法的调用后并不是立即执行多线程代码,而是使得该线程变为可运行态(Runnable),什么时候运行是由操作系统决定的。

从程序运行的结果可以发现,多线程程序是乱序执行。因此,只有乱序执行的代码才有必要设计为多线程。

Thread.sleep()方法调用目的是不让当前线程独自霸占该进程所获取的CPU资源,以留出一定时间给其他线程执行的机会。

实际上所有的多线程代码执行顺序都是不确定的,每次执行的结果都是随机的。

四、实现java.lang.Runnable接口

/** * 通过实现 Runnable 接口实现多线程 */ public class TestMitiThread1 implements Runnable {

public static void main(String[] args){ System.out.println(Thread.currentThread().getName()+ “ 线程运行开始!”);TestMitiThread1 test = new TestMitiThread1();Thread thread1 = new Thread(test);Thread thread2 = new Thread(test);thread1.start();thread2.start();System.out.println(Thread.currentThread().getName()+ “ 线程运行结束!”);}

public void run(){ System.out.println(Thread.currentThread().getName()+ “ 线程运行开始!”);for(int i = 0;i < 10;i++){ System.out.println(i + “ ” + Thread.currentThread().getName());try { Thread.sleep((int)Math.random()* 10);} catch(InterruptedException e){ e.printStackTrace();} } System.out.println(Thread.currentThread().getName()+ “ 线程运行结束!”);} }

运行结果:

main 线程运行开始!Thread-0 线程运行开始!main 线程运行结束!0 Thread-0 Thread-1 线程运行开始!0 Thread-1 1 Thread-1 1 Thread-0 2 Thread-0 2 Thread-1 3 Thread-0 3 Thread-1 4 Thread-0 4 Thread-1 5 Thread-0 6 Thread-0 5 Thread-1 7 Thread-0 8 Thread-0 6 Thread-1 9 Thread-0 7 Thread-1 Thread-0 线程运行结束!8 Thread-1 9 Thread-1 Thread-1 线程运行结束!说明:

TestMitiThread1类通过实现Runnable接口,使得该类有了多线程类的特征。run()方法是多线程程序的一个约定。所有的多线程代码都在run方法里面。Thread类实际上也是实现了Runnable接口的类。

在启动的多线程的时候,需要先通过Thread类的构造方法Thread(Runnable target)构造出对象,然后调用Thread对象的start()方法来运行多线程代码。

实际上所有的多线程代码都是通过运行Thread的start()方法来运行的。因此,不管是扩展Thread类还是实现Runnable接口来实现多线程,最终还是通过Thread的对象的API来控制线程的,熟悉Thread类的API是进行多线程编程的基础。

五、读解Thread类API

static int MAX_PRIORITY 线程可以具有的最高优先级。static int MIN_PRIORITY 线程可以具有的最低优先级。static int NORM_PRIORITY 分配给线程的默认优先级。

构造方法摘要

Thread(Runnable target)分配新的 Thread 对象。Thread(String name)分配新的 Thread 对象。

方法摘要

static Thread currentThread()返回对当前正在执行的线程对象的引用。ClassLoader getContextClassLoader()返回该线程的上下文 ClassLoader。long getId()返回该线程的标识符。String getName()返回该线程的名称。int getPriority()返回线程的优先级。Thread.State getState()返回该线程的状态。ThreadGroup getThreadGroup()返回该线程所属的线程组。static boolean holdsLock(Object obj)当且仅当当前线程在指定的对象上保持监视器锁时,才返回 true。void interrupt()中断线程。

static boolean interrupted()测试当前线程是否已经中断。boolean isAlive()测试线程是否处于活动状态。boolean isDaemon()测试该线程是否为守护线程。boolean isInterrupted()测试线程是否已经中断。void join()等待该线程终止。void join(long millis)等待该线程终止的时间最长为 millis 毫秒。void join(long millis, int nanos)等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒。void resume()已过时。该方法只与 suspend()一起使用,但 suspend()已经遭到反对,因为它具有死锁倾向。有关更多信息,请参阅为何 Thread.stop、Thread.suspend 和 Thread.resume 遭到反对?。void run()如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。void setContextClassLoader(ClassLoader cl)设置该线程的上下文 ClassLoader。void setDaemon(boolean on)将该线程标记为守护线程或用户线程。

static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)设置当线程由于未捕获到异常而突然终止,并且没有为该线程定义其他处理程序时所调用的默认处理程序。void setName(String name)改变线程名称,使之与参数 name 相同。void setPriority(int newPriority)更改线程的优先级。

void setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)设置该线程由于未捕获到异常而突然终止时调用的处理程序。static void sleep(long millis)在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)。static void sleep(long millis, int nanos)在指定的毫秒数加指定的纳秒数内让当前正在执行的线程休眠(暂停执行)。void start()使该线程开始执行;Java 虚拟机调用该线程的 run 方法。void stop()已过时。该方法具有固有的不安全性。用 Thread.stop 来终止线程将释放它已经锁定的所有监视器(作为沿堆栈向上传播的未检查 ThreadDeath 异常的一个自然后果)。如果以前受这些监视器保护的任何对象都处于一种不一致的状态,则损坏的对象将对其他线程可见,这有可能导致任意的行为。stop 的许多使用都应由只修改某些变量以指示目标线程应该停止运行的代码来取代。目标线程应定期检查该变量,并且如果该变量指示它要停止运行,则从其运行方法依次返回。如果目标线程等待很长时间(例如基于一个条件变量),则应使用 interrupt 方法来中断该等待。有关更多信息,请参阅《为何不赞成使用 Thread.stop、Thread.suspend 和 Thread.resume?》。void stop(Throwable obj)已过时。该方法具有固有的不安全性。请参阅 stop()以获得详细信息。该方法的附加危险是它可用于生成目标线程未准备处理的异常(包括若没有该方法该线程不太可能抛出的已检查的异常)。有关更多信息,请参阅为何 Thread.stop、Thread.suspend 和 Thread.resume 遭到反对?。void suspend()已过时。该方法已经遭到反对,因为它具有固有的死锁倾向。如果目标线程挂起时在保护关键系统资源的监视器上保持有锁,则在目标线程重新开始以前任何线程都不能访问该资源。如果重新开始目标线程的线程想在调用 resume 之前锁定该监视器,则会发生死锁。这类死锁通常会证明自己是“冻结”的进程。有关更多信息,请参阅为何 Thread.stop、Thread.suspend 和 Thread.resume 遭到反对?。String toString()返回该线程的字符串表示形式,包括线程名称、优先级和线程组。static void yield()暂停当前正在执行的线程对象,并执行其他线程。

六、线程的状态转换图

线程在一定条件下,状态会发生变化。线程变化的状态转换图如下:

1、新建状态(New):新创建了一个线程对象。

2、就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。

3、运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。

4、阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:

(一)、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。

(二)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。

(三)、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

5、死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

七、线程的调度

1、调整线程优先级:Java线程有优先级,优先级高的线程会获得较多的运行机会。

Java线程的优先级用整数表示,取值范围是1~10,Thread类有以下三个静态常量: static int MAX_PRIORITY 线程可以具有的最高优先级,取值为10。static int MIN_PRIORITY 线程可以具有的最低优先级,取值为1。static int NORM_PRIORITY 分配给线程的默认优先级,取值为5。

Thread类的setPriority()和getPriority()方法分别用来设置和获取线程的优先级。

每个线程都有默认的优先级。主线程的默认优先级为Thread.NORM_PRIORITY。

线程的优先级有继承关系,比如A线程中创建了B线程,那么B将和A具有相同的优先级。JVM提供了10个线程优先级,但与常见的操作系统都不能很好的映射。如果希望程序能移植到各个操作系统中,应该仅仅使用Thread类有以下三个静态常量作为优先级,这样能保证同样的优先级采用了同样的调度方式。

2、线程睡眠:Thread.sleep(long millis)方法,使线程转到阻塞状态。millis参数设定睡眠的时间,以毫秒为单位。当睡眠结束后,就转为就绪(Runnable)状态。sleep()平台移植性好。

3、线程等待:Object类中的wait()方法,导致当前的线程等待,直到其他线程调用此对象的 notify()方法或 notifyAll()唤醒方法。这个两个唤醒方法也是Object类中的方法,行为等价于调用 wait(0)一样。

4、线程让步:Thread.yield()方法,暂停当前正在执行的线程对象,把执行机会让给相同或者更高优先级的线程。

5、线程加入:join()方法,等待其他线程终止。在当前线程中调用另一个线程的join()方法,则当前线程转入阻塞状态,直到另一个进程运行结束,当前线程再由阻塞转为就绪状态。

6、线程唤醒:Object类中的notify()方法,唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。选择是任意性的,并在对实现做出决定时发生。线程通过调用其中一个 wait 方法,在对象的监视器上等待。直到当前的线程放弃此对象上的锁定,才能继续执行被唤醒的线程。被唤醒的线程将以常规方式与在该对象上主动同步的其他所有线程进行竞争;例如,唤醒的线程在作为锁定此对象的下一个线程方面没有可靠的特权或劣势。类似的方法还有一个notifyAll(),唤醒在此对象监视器上等待的所有线程。注意:Thread中suspend()和resume()两个方法在JDK1.5中已经废除,不再介绍。因为有死锁倾向。

7、常见线程名词解释

主线程:JVM调用程序mian()所产生的线程。

当前线程:这个是容易混淆的概念。一般指通过Thread.currentThread()来获取的进程。后台线程:指为其他线程提供服务的线程,也称为守护线程。JVM的垃圾回收线程就是一个后台线程。

前台线程:是指接受后台线程服务的线程,其实前台后台线程是联系在一起,就像傀儡和幕后操纵者一样的关系。傀儡是前台线程、幕后操纵者是后台线程。由前台线程创建的线程默认也是前台线程。可以通过isDaemon()和setDaemon()方法来判断和设置一个线程是否为后台线程。

本文出自 “熔 岩” 博客,请务必保留此出处http://lavasoft.blog.51cto.com/62575/27069

第三篇:JAVA基础总结

JAVA基础总结

转眼间,已经来到这里学习半年了,而现在我们对于JAVA学习才算是真正的开始。一开始接触的时候我发现这个和C语言的基本语法几乎一模一样的,老师说:JAVA语言本来就是C++语言发展过来的,而C++是从C语言发展来的,C C++ 还有JAVA虽然是不同的三种语言,但是其实他们的基本语法是一样的,但是它们却有巨大的区别,这个区别主要是体现在思想上。

都说C语言是面向过程的语言,C++ C#和JAVA是面向对象的编程,其实就是思维方式稍微改了一下子,面向过程的语言主要是着重于算法,面向对象着重于逻辑而已。

这个教我们的老师是张成峰老师,张成峰是个很负责的老师,虽然JAVA基础其实和C语言基础差不多,但是仔细学学还是能找出很多不同的细节的,于是大家的问题就很多,张老师几乎就是手把手的教我们,所以整体来说JAVA基础学得挺扎实的。

我在这本书的学习不是挺好,联系得少了,所以对代码也不是特别熟悉。而且JAVA是一门重概念的书,对于我来说,概念是我的要害,理论知识也是我最怕学习的,所以学习这本书对我来说很是艰难,听了很久的课,代码写得出来,但是理论知识几乎一点也不明白,结果就造成了这次笔试考的不好。

笔试考的不好,机试也因为我的粗心没有考好,所以这次的成绩不好。

学习JAVA基础后,还要在学习的过程中对每个知识都要用心和细心,当然最该注重的地方就是应该提高我对理论知识的学习,要多看书,也要多敲敲代码,这些就是提高学习知识全面的方法。

下一本书学习的是JAVAOO算是JAVA的一个重要的内容了,这才会真正的接触JAVA的核心课程,在这本书里我要好好的理解理论知识,仔细的学习每个知识。

第四篇:Java基础总结

 基本数据类型

 变量单元直接存放数据

 赋值和传参的方式:传值,即传递副本

 比较相等使用关系运算符“==”

 引用数据类型

 变量单元存放引用即对象地址,而数据(对象)在另一内存区域存放。

 赋值和传参的方式:传引用(传递对象的地址),即传递对象本身。

 使用关系运算符“==”比较两个引用类型变量,比较的是地址,如果比较结果为

真,说明两个变量引用了同一对象。

 比较两个对象是否相等应使用equals方法

 Java是面向对象的语言,开发Java程序就是开发Java类,Java的变量定义、方法(函

数)和语句都必须在类中书写,“无类即无Java”。

 类的实例成员

属性(成员变量):直接定义在类体中的变量(注:在方法或语句块中定义的变量不是属性)

方法:直接定义在类体中的方法。

类成员:直接定义在类体中的内部类,即类成员。

注:对象的成员是从属于对象的,必须通过对象访问,在Java中不存在脱离对象和类而独立存在的属性和方法。

 类、方法、语句三者的关系:

类中包含方法,方法中包含语句;方法中不能嵌套方法;语句不能直接写在类体中。

 变量的作用域

 局部变量-方法的参数、方法体中定义的变量、语句块中定义的变量,仅在所定义的方法体或语句块中有效。

 属性-在整个类体中有效。

 公有的属性-其它类可以本类对象访问。

 私有的属性-仅限本类内访问

 局部变量(无论基本类型还是引用类型)在栈内存中,对象在堆内存中。注:引用类型的局部变量内存放是对象的引用(即地址),而对象在堆内存中。

 方法的重载-在同一类中多个方法同名的语法现象,方法重载应符合以下条件:

 方法同名

 参数有所不同(即类型、个数和顺序三者至少有一个不同)

注:方法是否重载不考虑返回类型等其它方面。

 包和访问修饰符

 包-类的目录结构,主要用途是方便类的管理。

 类的简称:不含包名的类名

 类的全限定名称(类的全称):带包名的类名。

 访问修饰符

 private-仅限本类内访问

 public-任何类都能够访问

 默认-限本包的类访问

 protected--限本包的类访问和子类的访问

 类的成员(属性、方法和成员内部类)可以使用四种访问修饰符,顶级外部类仅能

使用public和默认两种修饰符。

 数组

 基本类型的数组的元素放的是数据

 对象数据的元素放的是对象的引用

 二维数组实际上是一个维数组,而其每个元素又是一个一维数组。

 构造方法-与类名同名并且无返回类型的方法

 构造方法的作用是创建对象,仅能通过new关键字调用。

 类中未显式定义构造方法时,类中会有默认的构造方法(即一个public、无参的构

造方法);类中一旦定义显式定义构造方法,将不再产生默认的构造方法。

 构造方法可以重载

 构造方法只能可以使用四个访问修饰符,不可以使用其它修饰符(如static、final

等)。

 this关键字

 this表示本对象或对象自身的引用

 通过this可以调用本类的成员方法和属性

 通过this可以调用本类的构造方法,this调用构造方法的语句必须写在构造方法的第一句。

 实例成员和静态成员

 类的成员(属性、方法和成员类)可划分为静态成员和实例成员。

 实例成员是属于对象的,随着对象的创建而存在,随着对象的销毁而销毁。 静态成员是属于类的,随着类的加载而存在,随着类的销毁而销毁。

 使用static修饰的成员是静态成员,未使用static修饰的成员是实例成员。 静态成员内不能使用this关键字。

 this表示当前对象的引用。

 对象的初始化

 第一:实例属性赋默认值

 第二:实例属性赋初值

 第三:执行对象初始化块

 第四:执行构造方法

 类的初始化

 第一:静态属性赋默认值

 第二:静态属性赋初值

 第三:执行静态块

 继承的基本概念

 Java仅支持单继承

  如果一个类没有显式继承任何类,则隐式继承java.lang.Object类  子类拥有父类的一切,子类对象由两部分构成:父类对象部分和子类个性化的部分。 子类并不能访问父类的一切:  子类可以访问父类的public成员和protected成员  子类不可以访问父类的private成员  仅当子类与父类同在一包时,子类方可以访问父类的默认访问控制的成员。继承与类和对象的初始化  构造子类对象时,首先构造父类对象,其次构造子类个性化部分,两者共同构成完整的子类对象,即首先进行父类对象的初始化,在初始化子类对象(个性化)部分。 子类构造方法的执行首先调用父类的构造方法。 若在子类构造方法中无显式调用父类构造方法的语句,则系统默认调用父类中可访问的无参的构造方法,如果这时候父类中恰好没有这样的构造方法,则编译出错。 在子类的构造方法中可以通过super关键字调用父类构造方法。这样的调用语句只能出现在子类构造方法的第一句。 关于初始化的顺序  初始化父类  初始化子类  初始化父类对象  初始化子类对象 继承与类型转换  子类型对象可以自动转型为父类型  父类型引用某个子类型对象时,可以强制转化为这个具体的子类型 方法重写  在继承的情况下,子类的实例方法与父类的实例方法的方法名称、参数、返回类型、throws声明完全一致,并且该子类方法的访问权限不低于父类方法的访问权限,即方法重写(子类方法重写了父类方法),也称方法覆盖。 方法重写仅存在于父子类中的实例方法,静态方法没有重写的概念。 当通过子类型对象执行重写方法时,将始终表现为子类的行为,而且无论引用对象的变量是父类型还是子类型,也无论是直接调用还是通过父类型其它方法间接调用,都将如此。 final修饰的方法不可以被重写  final修饰的类不可以被继承 隐藏成员变量  如果子类和父类中定义了同名称的成员变量,则称子类隐藏了父类的成员变量  通过父类方法访问隐藏的成员变量时,将获得父类成员变量  通过子类方法访问隐藏的成员变量时,将获得子类成员变量  通过父类型的引用直接访问隐藏的成员变量时,将获得父类成员变量  通过子类型的引用直接访问隐藏的成员变量时,将获得子类成员变量 super关键字

 super仅能用于子类中表示本对象的父对象部分

 super可以调用父类型的构造方法

 Super可以调用父类的成员

 Super不可以使用在静态上下文中

 Super不可以做为参数传递,不可以做为返回值返回。

 当方法重写时,或父类成员变量被隐藏时,子类中只能通过super访问父类方法和

父类成员变量

 final关键字

 用于变量,表示变量的值不可改变

 用于类,表示类不可被继承

 用于方法,表示方法不可以被重写

 关于final变量的初始化时机

 局部变量:声明的时候初始化

 实例成员变量:声明、对象初始化块和构造方法三处之一

 静态成员变量:声明、静态块两处之一

 抽象类

 抽象类可以包含抽象方法,也可以不包含抽象方法

 含有抽象方法的类必须定义为抽象类

 抽象类有构造方法

 抽象类不能够实例化

 通过抽象类可以调用其静态成员

 抽象类是需要由子类继承的,因此抽象类不允许是final类

 抽象方法

 抽象方法没有方法体,包括一对空的大括号也不允许有

 抽象方法必须是实例方法,抽象方法不允许是final的 抽象类与继承

 抽象类可以被继承

 若抽象类的子类是非抽象类,则该子类必须实现(重写)其父类的所有抽象方法  若抽象类的子类也是抽象类,则该子类可以不实现(重写)其父类的全部或部分抽象

方法。

 接口

 接口也是数据类型,可以将其理解为“纯”抽象类

 接口不是类,也没有构造方法,不能够实例化

 接口中的属性一律是public、static、final的,并可以省略这三个关键字

 接口的方法一律是public、abstract的,并且可以省略这两个关键字

 接口中可以不包含任何属性和方法

 接口与实现

 接口不是类,因此接口与类的关系不是“继承”关系,而是“实现”关系,我们可

以将实现理解为继承(尽管这并不恰当)

 如果接口的实现类是抽象类,则该实现类可以不实现接口的全部或部分方法  如果接口的实现类是非抽象类,则该实现类必须实现接口的全部方法

 一个类可以实现多个接口

 接口与继承

 接口之间可以相互继承

 一个接口可以继承多个接口

 接口与类型转换

 接口的的子类型对象可以自动向上转型为接口类型

 接口的子类型指:是接口的实现类或者接口的子接口

 如果变量引用的对象实际是某个接口的实现类对象,而变量的类型不是这个接口的子类型,那么则可以强制转换为这个接口类型。

 异常的类层次结构

 Throwable错误类,表示不可恢复的致命错误

 Exception运行时异常,此类异常可以不做显式处理

 非运行时异常catch

 声明抛出 在方法头通过throws声明可能抛出的异常类型

 异常机制的五个关键字

 try catch finally throw throws

 如何使用

 try-catch

 try-catch-finally注:只要try执行,其对应的finally块才必然执行

 try-finally注:只要try执行,其对应的finally块才必然执行

 throw 主动抛出一个异常

 throws 用在方法声明头部,声明方法可能抛出异常

 finally代码块多用于书写资源回收代码

 Java集合类(集合框架)

 Collection接口

 List接口 允许重复元素,元素有索引序号,并按放入元素的次序编号

 ArrayList 线性表结构,查找快,增删慢

 LinkedList 链表结构,查找慢,增删快

 Vector 同步,查找、增删性能都不高。

 Set接口 不允许重复元素,元素无索引编号

 HashSet 元素散列存放

 TreeSet元素按自然顺序排序(即从小到大排序)

 Map接口

 HashMap

 允许null值和null键

 不同步

 Hashtable <--Properties

 不允许null值和null键

 同步

 内部类

第五篇:多核多线程题目总结

2.并行和并发的概念与区别:

-如果某个系统支持两个或多个动作(Action)同时存在,那么这个系统就是一个并发系统-如果某个系统支持两个或多个动作同时执行,那么这个系统就是一个并行系统

-并发程序可同时拥有两个或多个线程。如果程序能够并行执行,则一定是运行在多核处理器上,每个线程都将分配到一个独立的处理器核上。

-“并行”概念是“并发”概念的一个子集 3.并行计算技术的主要目的:

加速求解问题的速度

例如,给定某应用,在单处理器上,串行执行需要2 周,这个速度对一般的应用而言,是无法忍受的。于是,可以借助并行计算,使用100 台处理器,加速50 倍,将执行时间缩短为6.72 个小时。

提高求解问题的规模

例如,在单处理器上,受内存资源2GB的限制,只能计算10 万个网格,但是,当前数值模拟要求计算千万个网格。于是,也可以借助并行计算,使用100 个处理器,将问题求解规模线性地扩大100 倍。并行计算的主要目标:

在并行机上,解决具有重大挑战性计算任务的科学、工程及商业计算问题,满足不断增长的应用问题对速度和内存资源的需求。

4.并行计算的主要研究内容大致可分为四个方面:

并行机的高性能特征抽取

充分理解和抽取当前并行机体系结构的高性能特征,提出实用的并行计算模型和并行性能评价方法,指导并行算法的设计和并行程序的实现。

并行算法设计与分析

设计高效率的并行算法,将应用问题分解为可并行计算的多个子任务,并具体分析这些算法的可行性和效果。

并行实现技术

主要包含并行程序设计和并行性能优化。

并行应用

这是并行计算研究的最终目的。通过验证和确认并行程序的正确性和效率,进一步将程序发展为并行应用软件,应用于求解实际问题。同时,结合实际应用出现的各种问题,不断地改进并行算法和并行程序。5.并行程序执行时间

对各个进程,墙上时间可进一步分解为计算CPU时间、通信CPU时间、同步开销时间、同步导致的进程空闲时间

计算CPU时间:进程指令执行所花费的CPU时间,包括程序本身的指令执行占用的时间(用户时间)和系统指令花费的时间;

通信CPU时间:进程通信花费的CPU时间; 同步开销时间:进程同步花费的时间;

进程空闲时间:进程空闲时间是指并行程序执行过程中,进程所有空闲时间总和(如进程阻塞式等待其他进程的消息时。此时CPU通常是空闲的,或者处于等待状态)6.并行程序性能优化

最主要的是选择好的并行算法和通信模式

减少通信量、提高通信粒度

提高通信粒度的有效方法就是减少通信次数,尽可能将可以一次传递的数据合并起来一起传递

全局通信尽量利用高效集合通信算法

对于标准的集合通信,如广播、规约、数据散发与收集等,尽量调用MPI标准库函数 挖掘算法的并行度,减少CPU空闲等待

具有数据相关性的计算过程会导致并行运行的部分进程空闲等待.在这种情况下,可以考虑改变算法来消除数据相关性

7.顺序程序的特性

顺序性:处理机严格按照指令次序依次执行,即仅当一条指令执行完后才开始执行下一条指令;

封闭性:程序在执行过程中独占系统中的全部资源,该程序的运行环境只与其自身动作有关,不受其它程序及外界因素影响;

可再现性:程序的执行结果与执行速度无关,而只与初始条件有关,给定相同的初始条件,程序的任意多次执行一定得到相同的执行结果.8.并发程序特性

交叉性:程序并发执行对应某一种交叉,不同的交叉可能导致不同的计算结果,操作系统应当保证只产生导致正确结果的交叉,去除那些可能导致不正确结果的交叉;

非封闭性:一个进程的运行环境可能被其它进程所改变,从而相互影响;

不可再现性:由于交叉的随机性,并发程序的多次执行可能对应不同的交叉,因而不能期望重新运行的程序能够再现上次运行的结果。

10.Win32线程同步的实现

11.数据作用域对数据值的影响

12.分析程序的结果

13.并行区域编程与parallel for语句的区别

-并行区域采用了复制执行方式,将代码在所有的线程内各执行一次;

-循环并行化则是采用工作分配执行方式,将循环需做的所有工作量,按一定的方式分配给各个执行线程,全部线程执行工作的总合等于原先串行执行所完成的工作量。14.OpenMP提供三种不同的互斥锁机制: 临界区(critical)原子操作(atomic)由库函数来提供同步操作 int counter=0;#pragma omp parallel {

for(int i=0;i<10000;i++)

#pragma omp atomic //atomic operation

}

printf(“counter = %dn”,counter);

counter=20000 25.影响性能的主要因素

并行化代码在应用程序中的比率-OpenMP 本身的开销

-OpenMP 获得应用程序多线程并行化的能力,需要一定的程序库支持。在这些库程序对程序并行加速的同时也需要运行库本身-负载均衡

-局部性

在程序运行过程中,高速缓存将缓存最近刚刚访问过的数据及其相邻的数据。因此,在编写程序的时候,需要考虑到高速缓存的作用,有意地运用这种局部性带来的高速缓存的效率提高。-线程同步带来的开销

多个线程在进行同步的时候必然带来一定的同步开销,在使用多线程进行开发时需要考虑同步的必要性,消除不必要的同步,或者调整同步的顺序,就有可能带来性能上的提升。26.什么是MPI 消息传递接口(Message Passing Interface,简称MPI)是一种编程接口标准,而不是一种具体的编程语言。基本含义:MPI标准定义了一组具有可移植性的编程接口。

特征:

1、典型的实现包括开源的MPICH、LAM MPI以及不开源的INTEL MPI。

2、程序员设计好应用程序并行算法,调用这些接口,链接相应平台上的MPI库,即可实现基于消息传递的并行计算

27.MPICH的安装和配置 counter++;

28.MPI程序的四个基本函数-MPI_Init和MPI_Finalize MPI_Init初始化MPI执行环境,建立多个MPI进程之间的联系,为后续通信做准备。而MPI_Finalize则是结束MPI执行环境。这两个函数用来定义MPI程序的并行区-MPI_Comm_rank

用来标识各个MPI进程,两个函数参数:

MPI_Comm类型的通信域,表示参与计算的MPI进程组 &rank,返回调用进程在comm中的标识号-MPI_Comm_size 用来标识相应进程组中有多少个进程,有两个参数: MPI_Comm类型的通信域,标尺参与计算的MPI进程组 整型指针,返回相应进程组中的进程数

29.MPI的点对点通信

两个最重要的MPI函数MPI_Send和MPI_Recv。

-int MPI_SEND(buf, count, datatype, dest, tag, comm)这个函数的含义是向通信域comm中的dest进程发送数据。消息数据存放在buf中,类型是datatype,个数是count个。这个消息的标志是tag,用以和本进程向同一目的进程发送的其他消息区别开来。

-int MPI_RECV(buf,count,datatype,source,tag,comm,status)MPI_Recv绝大多数的参数和MPI_Send相对应,有相同的意义。唯一的区别就是MPI_Recv里面多了一个参数status。status主要显示接收函数的各种错误状态。30.消息管理7要素 发送或者接收缓冲区buf; 数据数量count; 数据类型datatype;

目标进程或者源进程destination/source; 消息标签tag; 通信域comm;.消息状态status,只在接收的函数中出现。31.MPI群集通信

群集通信是包含了一对多、多对一和多对多的进程通信模式。其最大特点是多个进程参与通信。常用的MPI群集通信函数: 同步

广播 聚集 播撒

下载【java总结】多线程(基础篇)(5篇)word格式文档
下载【java总结】多线程(基础篇)(5篇).doc
将本文档下载到自己电脑,方便修改和收藏,请勿使用迅雷等下载。
点此处下载文档

文档为doc格式


声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:645879355@qq.com 进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。

相关范文推荐

    《JAVA基础》基本概念总结

    《JAVA基础》基本概念总结 1、在JAVA中所有万物皆对象,所有的代码都要写在一个类中,在类中只能包含属性(变量)和方法(函数),其它代码必须写在某一个方法中,方法与方法之间是平行的,不......

    JAVA基础知识点总结

    1) 开发Java语言的公司? Sun (Sun Microsystems)太阳微电子公司开发 2) Java的3个版本? J2SE(Java2 Standard Edition) 标准版 J2EE(Java 2 Platform,Enterprise Edition) 企业......

    java基础总结大全(笔记)

    一、基础知识: 1、JVM、JRE和JDK的区别:JVM(Java Virtual Machine):java虚拟机,用于保证java的跨平台的特性。 java语言是跨平台,jvm不是跨平台的。JRE(Java Runtime Environmen......

    Java学习_基础总结

    现在学习JAVA的人越来越多!但是学的好的,能用到工作中去的却很少很少,下面就是我为大家总结归纳的一些JAVA学习基础,希望大家少走弯路,尽快投入到工作中去! Java 学习基础总结归......

    Java程序员面试中的多线程问题

    很多核心Java面试题来源于多线程(Multi-Threading)和集合框架 (Collections Framework),理解核心线程概念时,娴熟的实际经验是必需的。这篇文章收集了Java线程方面一些典型的......

    Java程序员面试中的多线程问题

    Java程序员面试中的多线程问题 摘要:很多核心Java面试题来源于多线程(Multi-Threading)和集合框架(Collections Framework),理解核心线程概念时,娴熟的实际经验是必需的。这篇......

    Java基础知识点总结-Ch1

    Java基础知识点总结 第一章 Java语言概述 1.面性对象语言的基本特征。 Java语言的特点。最大优势。 Java语言是区分大小写的。 2.Java虚拟机的核心。 环境变量classpath设置......

    Java基础语法总结2

    Java基础语法总结2 三、运算符 Java基 本 的 运 算 符 按功能分有 下 面 几 类 : 1.算 术 运 算 符 (+,-,*,/,%,++,--) Java对 加 运 算 符 进 行 了 扩 展 ,使 它 能 够......