Java Thread多线程

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.");

}

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值