JavaThread多线程
Java多线程例子1小例子
publicclassThreadDemo{
publicstaticvoidmain(String[]args){
newTestThread().start();
while(true){
System.out.println("main():"+Thread.currentThread().getName()+"isrunning");
}
}
}
classTestThreadextendsThread{
publicTestThread(){
super("zhuyong");//设置线程的名字,默认为“TestThread”
}
publicvoidrun(){
while(true){
System.out.println("TestThread:"+Thread.currentThread().getName()+"isrunning");
}
}
}
输出结果为写道
main():mainisrunning
TestThread:Thread-0isrunning
main():mainisrunning
TestThread:Thread-0isrunning
main():mainisrunning
TestThread:Thread-0isrunning
Java多线程例子2前台线程(用户线程)后台线程(守护线程)
1,setDaemon(true)后就是后台线程(守护线程),反之就是前台线程(用户线程)
2,后台线程和前台线程的区别:在java程序中如果所有的前台线程都已经退出,所有的后台线程自动退出。
publicclassThreadDemo{
publicstaticvoidmain(String[]args){
Threadt=newTestThread();
t.setDaemon(true);
t.start();
}
}
classTestThreadextendsThread{
publicvoidrun(){
while(true){
System.out.println("TestThread:"+Thread.currentThread().getName()+"isrunning");
}
}
}
运行当前台线程main退出后自动退出。去掉setDeamon,TestThread就不会退出
Java多线程例子3联合线程join()
a,直接联合:
publicclassThreadDemo{
publicstaticvoidmain(String[]args){
Threadt=newTestThread();
//t.setDaemon(true);
t.start();
try{
t.join();
}catch(InterruptedExceptione){
e.printStackTrace();
}
while(true){
System.out.println("main():"+Thread.currentThread().getName()+"isrunning");
}
}
}
classTestThreadextendsThread{
publicvoidrun(){
while(true){
System.out.println("TestThread:"+Thread.currentThread().getName()+"isrunning");
}
}
}
这种直接联合,2个线程就完全成了一个线程了。
b,条件联合:
publicclassThreadDemo{
publicstaticvoidmain(String[]args){
Threadt=newTestThread();
//t.setDaemon(true);
t.start();
inti=0;
while(true){
System.out.println("main():"+Thread.currentThread().getName()+"isrunning");
if(i++==10000){
try{
t.join();
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
}
}
}
classTestThreadextendsThread{
publicvoidrun(){
while(true){
System.out.println("TestThread:"+Thread.currentThread().getName()+"isrunning");
}
}
}
当main线程中工作10000下后,把线程TestThread联合进来,实际上就是main线程运行10000下后,一直等到TestThread完成后,再运行。
c,联合10秒和分开:
publicclassThreadDemo{
publicstaticvoidmain(String[]args){
Threadt=newTestThread();
//t.setDaemon(true);
t.start();
inti=0;
while(true){
System.out.println("main():"+Thread.currentThread().getName()+"isrunning");
if(i++==10000){
try{
t.join(10000);
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
}
}
}
classTestThreadextendsThread{
publicvoidrun(){
while(true){
System.out.println("TestThread:"+Thread.currentThread().getName()+"isrunning");
}
}
}
当main线程运行10000下后,与TestThread联合10秒,其实就是让TestThread运行10秒,然后在分别运行。
Java多线程例子4继承Thread实现Runnable
classTestThreadextendsThread{
publicvoidrun(){
while(true){
System.out.println("TestThread:"+Thread.currentThread().getName()+"isrunning");
}
}
}
classThreadDemo{
publicstaticvoidmain(String[]args){
TestThreadt=newTestThread();
newThread(t).start();
newThread(t).start();
newThread(t).start();
newThread(t).start();
}
}
classTestThreadimplementsRunnable{
inttickets=100;
publicvoidrun(){
while(true){
if(tickets<0)
break;
System.out.println(Thread.currentThread().getName()+"issaling"+tickets--);
}
}
}
这里模拟4个窗口,一起卖100张车票。新建一个线程可以通过继承Thread类或实现Runnable,几乎所有的线程实现都可以通过实现Runnable完成,而且该方法适合多个相同线程去处理同一个资源的情况,把虚拟的线程和数据有效分离,较好地体现了面向对象的设计思想。上面4个窗口一起卖100张票的例子有继承Thread的方法就不是太好实现。
Java多线程例子5实际例子的讨论
1,网络聊天程序,如QQ。
发送信息和接受信息肯定要连个线程,你不可能自己输入发送信息的时候就不能接受对方的信息了。
2,图形界面程序。
要说多线程用的最多的恐怕就要数图形程序了,图形程序每隔一段时间就要刷新一次,要不然大家是看不到图形的。
3,www网络服务器。
不可能每个网页只能在一个时间内让一个访问,实际上,网络服务器会为每个访问者建立一个专属的线程。
其实,线程在计算机中的运行中本没有实现真正的并行运行,最终还是由cpu交替运行这些线程,所以我觉得如果说对于单CPU来说的话多线程提高了效率那是不对的。那么在什么样的情况下需要使用多线程呢,现在我先总结成,在一个程序中需要有多个事情长期存在,而且这些事情都会存在等待的情况,我们就可以采用多线程的技术来实现貌似这些事情都并行的程序了。
看上面举得例子是不是这种情况呢?
第一,网络聊天程序,讨论的是发送信息和接受信息这两件事,首先这两件事都是长期存在的,不可能发了一个信息就不发了,然后看是不是这两件事是不是都存在等待呢,发送不可能总在发送吧,同样对方也不可能总在发送这边就不可能总在接受了,两件事情都存在等待,发送是要等待用户输入信息,接受要等待对方发送信息。
第二,图形界面,比如一个图形界面中有两个按钮,就像两件事情,这两个按钮都长时间存在,而且都在等待用户的按键。
第三,网络服务器多个用户长时间访问这个网页,网络服务器等待这些用户与服务器交互。
总结:需要用多线程=多任务共存长时间+多任务存在等待时间
Java多线程例子6线程安全线程同步同步代码块同步函数
线程安全
出现线程安全就是在使用多线程的时候程序出现了不期望的结果。
怎样思考线程安全:线程中任何一步运行完都可能交出CPU的控制权。
classThreadDemo{
publicstaticvoidmain(String[]args){
TestThreadt=newTestThread();
newThread(t).start();
newThread(t).start();
newThread(t).start();
newThread(t).start();
}
}
classTestThreadimplementsRunnable{
inttickets=100;
publicvoidrun(){
while(true){
if(tickets<=0)
break;
//try{Thread.sleep(10);}catch(Exceptione){}
System.out.println(Thread.currentThread().getName()
+"issaling"+tickets--);
}
}
}
例子展示了四个售票员一起卖这100张票,那么卖出同样序号的票是我们不期望看到了情况吧,上面已经提到了,分析线程安全的最基本的方法就是认为线程运行的时候任何情况下都可以交出CPU的控制权,上面一共启动了4个线程,现在假设tickets的值为1时,线程1在运行完“if(tickets<=0)”后交出CPU,后线程2得到了CPU,卖出了票1,后线程1重新得到了CPU,又卖出了票1或0。当然,上述情况是我们假设在什么情况下会出现象这样的线程安全的问题,在一般情况,我们运行这个程序好几次也不能看出这样的线程安全问题,那我们怎么确定这个问题呢?我们可以用“sleep(100)”来主动交出CPU来验证我们的想法:去掉上面注释的sleep再运行程序,得到
运行结果写道
Thread-1issaling2
Thread-2issaling1
Thread-3issaling0
Thread-0issaling-1
Thread-1issaling-2
卖出了0、-1和-2的票,证明上述这种写法是存在线程安全的。
线程同步
为了解决线程安全的问题,就要引入线程同步。
classThreadDemo{
publicstaticvoidmain(String[]args){
TestThreadt=newTestThread();
newThread(t).start();
newThread(t).start();
newThread(t).start();
newThread(t).start();
}
}
classTestThreadimplementsRunnable{
inttickets=100;
Stringstr="";//此时str为公共对象
publicvoidrun(){
while(true){
synchronized(str){
if(tickets<=0)
break;
//try{Thread.sleep(10);}catch(Exceptione){}
System.out.println(Thread.currentThread().getName()
+"issaling"+tickets--);
}
}
}
}
在上面的代码中加入synchronized,就可以实现线程同步了。
运行结果写道
hread-2issaling5
hread-3issaling4
hread-1issaling3
hread-0issaling2
hread-2issaling1
这个线程同步怎么理解呢?这里有个锁旗标的概念,锁旗标可以理解为java中的每一个对象都有个标志位,该标志位开始的状态是1,当执行完synchronized后这个对象的标志位被置为了0,这个过程就说这个线程得到了这个对象的锁旗标,synchronized块运行完之后这个线程会让出这个对象的锁旗标,而每个线程在遇到synchronized是都回查看这个对象的锁旗标在不在,如果不在该线程就会主要让出CPU。
这里还要记住synchronized的对象一定要是多个线程的公共对象,要是各自的对象就不能实现同步了。如下面改变str定义的位置。
classThreadDemo{
publicstaticvoidmain(String[]args){
TestThreadt=newTestThread();
newThread(t).start();
newThread(t).start();
newThread(t).start();
newThread(t).start();
}
}
classTestThreadimplementsRunnable{
inttickets=100;
publicvoidrun(){
Stringstr="";//此时str为私有对象
while(true){
synchronized(str){
if(tickets<=0)
break;
//try{Thread.sleep(10);}catch(Exceptione){}
System.out.println(Thread.currentThread().getName()
+"issaling"+tickets--);
}
}
}
}
结果为写道
Thread-1issaling2
Thread-2issaling1
Thread-3issaling0
Thread-0issaling-1
Thread-1issaling-2
另外,在运行加入了synchronized同步块的程序的时会发现速度明显比没有同步块的程序要慢的多,所以在确定不会出现线程安全问题的程序中不要加入同步块,就像我们经常先使用Vector还是有ArrayList呢?它们两个的功能基本是完全一样的都是List,而Vector中的函数考虑了线程同步,ArrayList没有,这下就非常明显了,如果需要保证线程安全是就用Vector,不需要就用ArrayList效率高些。
同步函数
同步函数实现
classThreadDemo{
publicstaticvoidmain(String[]args){
TestThreadt=newTestThread();
newThread(t).start();
newThread(t).start();
newThread(t).start();
newThread(t).start();
}
}
classTestThreadimplementsRunnable{
inttickets=100;
publicvoidrun(){
while(true){
sale();
}
}
publicsynchronizedvoidsale(){
if(tickets<=0)
return;
try{Thread.sleep(10);}catch(Exceptione){}
System.out.println(Thread.currentThread().getName()
+"issaling"+tickets--);
}
}
同步函数实际上同步的是this对象,这样如果要想某一个同步块和一个同步函数同步,就在同步块中使用this对象。
Java多线程例子7线程安全死锁
死锁:在多个线程里对多个同步对象具有循环依赖时常会出现死锁。最简单的死锁例子就是线程一得到了A对象的锁旗标想得到B对象的锁旗标,线程二得到了B对象的锁旗标想得到A对象的锁旗标,这样线程一和线程二就形成了死锁。
classThreadDemo{
publicstaticvoidmain(String[]args){
TestThreadt=newTestThread();
newThread(t).start();
try{Thread.sleep(10);}catch(Exceptione){}
t.flag=true;
newThread(t).start();
}
}
classTestThreadimplementsRunnable{
booleanflag=false;
StringA=newString("");
StringB=newString("");
//StringA="";
//StringB="";
publicvoidrun(){
System.out.println(A==B);
if(flag){
while(true){
synchronized(A){
try{Thread.sleep(100);}catch(Exceptione){}
synchronized(B){}
}
System.out.println("AA...running...");
}
}else{
while(true){
synchronized(B){
try{Thread.sleep(100);}catch(Exceptione){}
synchronized(A){}
}
System.out.println("BB...running...");
}
}
}
}
这里启动了两个线程,两个线程都循环想要得到A对象和B对象的锁旗标。
在试验这个例子的时候,还遇到了一个有意思的问题:刚开始我用的A和B对象是这么写的A="";B="";结果死活实验不出来死锁问题,这倒是挺奇怪的。结果最后发现原来这时候A和B引用了同一个对象,这是更java中对字符串常量的处理有关系,A="";时,java会在堆中建立一个字符串常量,这个字符串常量为空,由A引用,在B="",java发现字符串常量中有这么一个空字符串常量就不会新建了。
Java多线程例子8线程状态
在JDK的电子书中搜索Thread.State可以找到。
publicstaticenumThread.StateextendsEnum<Thread.State>线程状态。线程可以处于下列状态之一:
1.NEW
至今尚未启动的线程的状态。
2.RUNNABLE
可运行线程的线程状态。处于可运行状态的某一线程正在Java虚拟机中运行,但它可能正在等待操作系统中的其他资源,比如处理器。
3.BLOCKED
受阻塞并且正在等待监视器锁的某一线程的线程状态。处于受阻塞状态的某一线程正在等待监视器锁,以便进入一个同步的块/方法,或者在调用Object.wait之后再次进入同步的块/方法。
4.WAITING
某一等待线程的线程状态。某一线程因为调用下列方法之一而处于等待状态:
·不带超时值的Object.wait
·不带超时值的Thread.join
LockSupport.park
处于等待状态的线程正等待另一个线程,以执行特定操作。例如,已经在某一对象上调用了Object.wait()的线程正等待另一个线程,以便在该对象上调用Object.notify()或Object.notifyAll()。已经调用了Thread.join()的线程正在等待指定线程终止。
5.TIMED_WAITING具有指定等待时间的某一等待线程的线程状态。某一线程因为调用以下带有指定正等待时间的方法之一而处于定时等待状态:
·Thread.sleep
·带有超时值的Object.wait
·带有超时值的Thread.join
·LockSupport.parkNanos
·LockSupport.parkUntil
6.TERMINATED
已终止线程的线程状态。线程已经结束执行。
注意:在给定时间点上,一个线程只能处于一种状态。这些状态是虚拟机状态,它们并没有反映所有操作系统线程状态。
为了展现线程在运行时的状态及其转换,我画了下面这个图:
Java多线程例子9线程之间通信waitnotifynotifyAll
程序实现了一个生产者和一个消费者,还有一个buffer用于存放生产出来的一个对象,buffer中只可以存放一个对象,buffer有一个标志位bFull,如果标志位为true表示buffer里有数值,如果bFull为false表示没有数值。buffer中的对象有两个属性,在多线程中如果不处理同步的话,可能出现属性不对应的情况。
wait:告诉当前线程放弃监视器并进入睡眠状态,直到其他线程进入同一监视器并调用notify为止。
notify:唤醒同一对象监视器中调用wait的第一线程。用于类似饭馆有一个空位子后通知所有等候就餐的顾客中的第一位可以入座的情况。
notifyAll:唤醒同一对象监视器中调用wait的所有线程,具有最高优先级的线程首先被唤醒并执行。用于类似某个不定期的培训班终于招生满额后,通知所有学员都来上课的情况。
从上面明显可以看出wait、notify和notifyAll只能在synchronized方法中调用,记住一个对象的notify只能够唤醒被同一个对象wait的线程。
classThreadDemo{
publicstaticvoidmain(String[]args){
Bufferbuf=newBuffer();
newProducer(buf).start();
newConsumer(buf).start();
}
}
classProducerextendsThread{
privateBufferbuf;
publicProducer(Bufferbuf){
this.buf=buf;
}
publicvoidrun(){
booleanodd=false;
while(true){
synchronized(buf){
if(buf.bFull)
try{buf.wait();}catch(Exceptione){}
if(odd){
buf.name="jack";
try{Thread.sleep(100);}catch(Exceptione){}
buf.sex="female";
}else{
buf.name="lucy";
try{Thread.sleep(100);}catch(Exceptione){}
buf.sex="male";
}
buf.bFull=true;
buf.notify();
}
odd=!odd;
}
}
}
classConsumerextendsThread{
privateBufferbuf;
publicConsumer(Bufferbuf){
this.buf=buf;
}
publicvoidrun(){
while(true){
synchronized(buf){
if(!buf.bFull)
try{buf.wait();}catch(Exceptione){}
//try{Thread.sleep(100);}catch(Exceptione){}
System.out.println(buf.name+":"+buf.sex);
buf.bFull=false;
buf.notify();
}
}
}
}
classBuffer{
booleanbFull=false;
Stringname="Unkown";
Stringsex="Unkown";
}
结果写道
lucy:male
jack:female
lucy:male
jack:female
lucy:male
jack:female
面前对象同步函数
classThreadDemo{
publicstaticvoidmain(String[]args){
Bufferbuf=newBuffer();
newProducer(buf).start();
newConsumer(buf).start();
}
}
classProducerextendsThread{
privateBufferbuf;
publicProducer(Bufferbuf){
this.buf=buf;
}
publicvoidrun(){
booleanodd=false;
while(true){
if(odd){
buf.put("jack","female");
}else{
buf.put("lucy","male");
}
odd=!odd;
}
}
}
classConsumerextendsThread{
privateBufferbuf;
publicConsumer(Bufferbuf){
this.buf=buf;
}
publicvoidrun(){
while(true){
buf.get();
}
}
}
classBuffer{
privatebooleanbFull=false;
privateStringname="Unkown";
privateStringsex="Unkown";
publicsynchronizedvoidput(Stringname,Stringsex){
if(bFull)
try{wait();}catch(Exceptione){}
this.name=name;
this.sex=sex;
bFull=true;
notify();
}
publicsynchronizedvoidget(){
if(!bFull)
try{wait();}catch(Exceptione){}
System.out.println(name+":"+sex);
bFull=false;
notify();
}
}
Java多线程例子10控制线程的生命stop
在Thread类中stop已经不推荐大家使用了,因为使用stop停止的线程不安全,它并不会释放被该线程锁定的对象的锁旗标,这样其它线程如果也想要得到该对象的锁旗标就永远得不到了,形成死锁了。
利用标志位控制线程的生命周期:
publicclassthreadtest{
publicstaticvoidmain(String[]args){
Thread1t=newThread1();
t.start();
try{Thread.sleep(1);}catch(Exceptione){};
for(inti=0;i<10;i++){
System.out.println("main"
+"isrunning.");
if(i==5)
t.stopMe();
}
}
}
classThread1extendsThread{
privatebooleanbStop=false;
publicvoidstopMe(){
this.bStop=true;
}
publicvoidrun(){
while(!bStop){
System.out.println(Thread.currentThread().getName()
+"isrunning.");
}
}
}
相关推荐
Java Thread多线程全面解析涵盖了Java编程中关于线程的重要概念和实践技巧。在Java中,多线程是并发编程的基础,允许程序同时执行多个任务,提高系统资源利用率和应用程序的响应速度。 线程的生命周期包括五个基本...
继承Thread类: 1必须重写run 方法:里面放置的实际的线程体 2 启动线程: 3创建Thread对象 4调用Thread对象的start 方法启动线程
2. **JAVA多线程API**:论文会详细阐述JAVA提供的多线程API,如Thread类、Runnable接口、ExecutorService和Future接口等。通过实例解析这些类和接口的使用方法,帮助读者理解如何在实际编程中创建和管理线程。 3. *...
最后,Java并发库还包含了很多其他有用的工具,如Semaphore(信号量)用于控制同时访问特定资源的线程数量,CyclicBarrier(循环屏障)和CountDownLatch(计数器门锁)用于多线程间的协作,以及Lock接口及其实现如...
Java虚拟机(JVM)支持多线程,无论运行在何种操作系统上,Java程序都可以利用Thread类创建和管理线程。每个线程由虚拟CPU、执行的程序代码和处理的数据三部分组成。通过创建Thread类的实例,我们可以启动、控制和...
在 Java 中,多线程编程可以通过 Thread 类和 Runnable 接口来实现。 为什么需要多线程? 在单线程程序中,如果某个任务需要很长时间来执行,那么整个程序将被阻塞,无法响应用户的其他请求。使用多线程编程可以...
Java多线程机制是Java编程中至关重要的一部分,它允许程序同时执行多个任务,提升应用程序的效率和响应性。以下是对各个知识点的详细说明: 9.1 Java中的线程: Java程序中的线程是在操作系统级别的线程基础上进行...
Java通过Thread类和Runnable接口来支持多线程。创建一个新线程通常有两种方式:继承Thread类并重写run()方法,或者实现Runnable接口并提供run()方法。在run()方法中编写线程执行的代码。 进度条通常由主线程负责...
### Java多线程操作数据库:深入解析与应用 在当今高度并发的应用环境中,Java多线程技术被广泛应用于处理数据库操作,以提升系统的响应速度和处理能力。本文将基于一个具体的Java多线程操作数据库的应用程序,深入...
Java多线程是Java编程语言中一个非常重要的概念,它允许开发者在一个程序中创建多个执行线程并行运行,以提高程序的执行效率和响应速度。在Java中,线程的生命周期包含五个基本状态,分别是新建状态(New)、就绪...
在Java中,实现多线程有两种主要方式:继承Thread类和实现Runnable接口。 1. 继承Thread类: 当我们创建一个新的类,让它继承Thread类时,可以通过重写`run()`方法来定义线程执行的任务。然后创建该类的对象,并...
Java多线程是Java编程中的重要概念,尤其在如今的多核处理器环境下,理解并熟练掌握多线程技术对于提高程序性能和响应速度至关重要。本资料详细讲解了Java多线程的原理,并提供了丰富的实战代码,非常适合Java初学者...
### Java多线程分页查询知识点详解 #### 一、背景与需求分析 在实际的软件开发过程中,尤其是在处理大量数据时,如何高效地进行数据查询成为了一个关键问题。例如,在一个用户众多的社交平台上,当用户需要查看...
总之,Java中的多线程通过Thread类和Runnable接口实现,通过`synchronized`关键字确保线程安全,利用`wait()`, `notify()`, 和 `notifyAll()`进行线程间通信,有效地提高了程序的并发性能和资源利用率。在编写多线程...
在Java编程中,多线程并发是提升程序执行效率、充分利用多核处理器资源的重要手段。本文将基于"java 多线程并发实例"这个主题,深入探讨Java中的多线程并发概念及其应用。 首先,我们要了解Java中的线程。线程是...
Java多线程与并发编程是Java开发中至关重要的一部分,它涉及到如何高效地利用CPU资源,以实现程序的并行执行。在操作系统层面,多任务和多进程是通过分配不同的内存空间来实现的,而线程则共享同一进程的内存,这...
Java Socket 多线程是网络编程中的一个重要概念,它结合了Java的并发处理能力和Socket通信技术,使得服务器能够同时处理多个客户端的连接请求。在Java中,Socket是用于在网络环境中进行双向通信的类,而多线程则允许...
在Java中,实现多线程有两种主要方式:通过实现Runnable接口或者继承Thread类。本案例将深入探讨Java多线程中的关键知识点,包括线程同步、线程通信和线程阻塞。 线程同步是为了防止多个线程同时访问共享资源,导致...
在Java编程中,多线程处理是提升程序性能和效率的重要手段,特别是在处理大量数据库数据时。本主题将深入探讨如何使用Java的并发包(java.util.concurrent)来实现多线程对数据库数据的批量处理,包括增、删、改等...
在Java编程中,多线程是一项关键特性,它允许程序同时执行多个任务,极大地提高了效率。本实例将探讨如何利用Java实现一个具有进度条显示功能的多线程应用。进度条通常用于可视化地表示某个任务的完成程度,这对于长...