多线程.docx
《多线程.docx》由会员分享,可在线阅读,更多相关《多线程.docx(21页珍藏版)》请在冰豆网上搜索。
![多线程.docx](https://file1.bdocx.com/fileroot1/2023-1/23/01a033f2-3981-4d06-afb8-67845399d1ec/01a033f2-3981-4d06-afb8-67845399d1ec1.gif)
多线程
一.进程和线程
2.单线程与多线程
1.单线程
TestThread.class
publicclassTestThread{
publicvoidrun(){
while(true){
System.out.println("test"+Thread.currentThread().getName());
}
}
}
Threaddemo1
publicclassThreaddemo1{
publicstaticvoidmain(String[]args){
newTestThread().run();
while(true){
/*Thread就代表线程,Thread类中有一个静态方法叫currentThread,
*这个方法会返回一个线程类的对象,一个线程类对象代表一个线程
*这个返回的线程类对象就代表mian方法执行时所处于的那个线程
*每个线程都有个名称可以用线程对象的getName方法获得
*/
System.out.println("main"+Thread.currentThread().getName());
//结果是testmain
//不会执行main方法中的while语句,这就是单线程
}
}
}
2.用Thread类创建线程
TestThread.class
publicclassTestThreadextendsThread{
publicvoidrun(){
while(true){
System.out.println("test"+Thread.currentThread().getName());
}
}
}
Threaddemo1.class
publicclassThreaddemo1{
publicstaticvoidmain(String[]args){
//newThread().start();
newTestThread().start();
//多线程,执行while里面的方法交替执行
while(true){
System.out.println("main"+Thread.currentThread().getName());
}
}
}
3.后台线程与联合线程
1.后台线程
TestThread.class
publicclassTestThreadextendsThread{
publicvoidrun(){
while(true){
System.out.println("test"+Thread.currentThread().getName());
}
}
}
Threaddemo1.class
publicclassThreaddemo1{
publicstaticvoidmain(String[]args){
//newThread().start();
//只要还有一个前台线程,我们的java程序就不会结束
Threadt1=newThread();
//调用setDaemon并且传true进去,就变成了后台线程
//没有了前台线程,后台线程也不在执行
t1.setDaemon(true);
t1.start();
}
}
2.合并线程
Threaddemo1.class
publicclassThreaddemo1{
publicstaticvoidmain(String[]args){
//newThread().start();
//只要还有一个前台线程,我们的java程序就不会结束
Threadt1=newTestThread();
//调用setDaemon并且传true进去,就变成了后台线程
//没有了前台线程,后台线程也不在执行
//t1.setDaemon(true);
t1.start();
intdex=0;
while(true){
dex++;
if(dex==100){
try{
t1.join();//join来合并线程
}catch(InterruptedExceptione){
//TODOAuto-generatedcatchblock
}
}
System.out.println("main"+Thread.currentThread().getName());
}
}
}
TestThread.class
publicclassTestThreadextendsThread{
publicvoidrun(){
while(true){
System.out.println("test"+Thread.currentThread().getName());
}
}
}
3.分开线程
4.Thread(Runnabletarget)
Runnable是一个接口,里面只有一个run方法。
这个时候调用Thread的start方法时,就不在启动Thread的run方法,而是启动runnable里面的run方法。
5.Thread()和Thread(Runnabletarget)创建多线程的区别
模拟铁路售票系统,实现4个售票处发售100张某日某次列车的票,一个售票处用一个线程来表示:
(1)Thread():
结果是4个线程都买了100张票,线程一卖了1号票,线程2也卖了一号票。
这样每个线程都卖了1号票。
这四个线程不是在卖共同的100张票,而是各卖各的100张票。
Threaddemo1.class
publicclassThreaddemo1{
publicstaticvoidmain(String[]args){
newTestThread().start();
newTestThread().start();
newTestThread().start();
newTestThread().start();
/*
如果使用下面这种情况是启动一个线程去卖100张票,没有启动4个线程。
TestThreadt1=newTestThread();
t1.start();
t1.start();
t1.start();
t1.start();
*/
}
}
TestThread.class
publicclassTestThread/*implementsRunnable*/extendsThread{
inttickets=100;
publicvoidrun(){
while(true){
if(tickets>0){
System.out.println(Thread.currentThread().getName()+"issalingticket"+tickets--);
}else{
break;
}
}
}
}
(2)Thread(Runnabletarget)
创建了4个线程使用同一个资源,这样就是4个线程共同卖100张票。
每2个线程间不能卖同一张票。
Threaddemo1.class
publicclassThreaddemo1{
publicstaticvoidmain(String[]args){
TestThreadt1=newTestThread();
newThread(t1).start();
newThread(t1).start();
newThread(t1).start();
newThread(t1).start();
}
}
TeatThread.class
publicclassTestThreadimplementsRunnable{
inttickets=100;
publicvoidrun(){
while(true){
if(tickets>0){
System.out.println(Thread.currentThread().getName()+"issalingticket"+tickets--);
}else{
break;
}
}
}
}
3.案例
(1)
4.多线程的同步的问题
1.有可能售票卖到5时,系统执行tickets--时切到了另一个线程,这样另一个线程也会再卖一次5号票,这样5号票被卖了2次,4号票就没了。
(1)实现同步的方法是synchronized同步代码
publicclassTestThreadimplementsRunnable{
inttickets=100;
Stringstr=newString("");
publicvoidrun(){
while(true){
synchronized(str){//synchronized同步代码块,表示synchronized中的代码必须一次执行,不会分开执行。
//synchronized()括号里要传递一个对象,可以是任意的对象
if(tickets>0){
//try{
//Thread.sleep(10);
//}catch(InterruptedExceptione){
////TODOAuto-generatedcatchblock
//e.printStackTrace();
//}
System.out.println(Thread.currentThread().getName()+"issalingticket"+tickets--);
}else{
break;
}
}
}
}
}
(2)使用synchronized来定义同步方法实现同步
publicclassTestThreadimplementsRunnable{
inttickets=100;
Stringstr=newString("");
publicvoidrun(){
sale();
}
publicsynchronizedvoidsale(){
while(true){
if(tickets>0){
//try{
//Thread.sleep(10);
//}catch(InterruptedExceptione){
////TODOAuto-generatedcatchblock
//e.printStackTrace();
//}
System.out.println(Thread.currentThread().getName()+"issalingticket"+tickets--);
}else{
break;
}
}
}
}
(3)同步代码块与同步方法块同步(要使用同样的标识对象)
1).失败案例
运行的结果是sale方法的输出,并没有运行代码块里面的代码
Threaddemo1.class
publicclassThreaddemo1{
publicstaticvoidmain(String[]args){
TestThreadt1=newTestThread();
newThread(t1).start();//只是启动线程不一定会马上执行
t1.str=newString("System");
//所以本行语句有可能先执行,在执行线程里面的run方法
//这个时候的str已经变成System了,执行的是sale方法里的代码
newThread(t1).start();
newThread(t1).start();
newThread(t1).start();
}
}
TestThread.class
publicclassTestThreadimplementsRunnable{
inttickets=100;
Stringstr=newString("");
publicvoidrun(){
if(str.equals("System")){
while(true){
sale();
}
}else{
while(true){
synchronized(str){
if(tickets>0){
try{
Thread.sleep(10);
}catch(InterruptedExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"ttissalingticket"+tickets--);
}
}
}
}
}
publicsynchronizedvoidsale(){
if(tickets>0){
try{
Thread.sleep(10);
}catch(InterruptedExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"issalingticket"+tickets--);
}
}
}
2).同步方法的标识对象是this,所以只有把同步代码块中的传递的对象改成this,同步方法和同步代码块就可以同步了
Threaddemo1.class
publicclassThreaddemo1{
publicstaticvoidmain(String[]args){
TestThreadt1=newTestThread();
newThread(t1).start();
//try{
//Thread.sleep
(1);
//}catch(InterruptedExceptione){
////TODOAuto-generatedcatchblock
//e.printStackTrace();
//}
t1.str=newString("System");
newThread(t1).start();
newThread(t1).start();
newThread(t1).start();
}
}
TestThread.class
publicclassTestThreadimplementsRunnable{
inttickets=100;
Stringstr=newString("");
publicvoidrun(){
if(str.equals("System")){
while(true){
sale();
}
}else{
while(true){
synchronized(this){
if(tickets>0){
try{
Thread.sleep(10);
}catch(InterruptedExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"ttissalingticket"+tickets--);
}
}
}
}
}
publicsynchronizedvoidsale(){
if(tickets>0){
try{
Thread.sleep(10);
}catch(InterruptedExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"issalingticket"+tickets--);
}
}
}
(4).死锁问题
通常都是一个线程进入了x的监视器,另外一个线程进入了y的监视器,刚开是的线程进入了x的监视器以后,接着等待y的监视器,第二个线程进入了y的监视器又在等待x的监视器,这样子就会导致我们的第一个线程等不到y的监视器,第二个线程等到x的监视器。
这就是处于死锁,程序就会停滞不前。
多线程共享同一数据或同一对象(也就是多个线程的代码访问了同一个数据或对象)的时候就会发生线程安全的问题,我们在编写线程安全的程序代码时候,也必须防止一个线程对共享的数据仅仅是做了部分的操作,那个线程就结束了,这个时候就会破坏那个数据的一致性,再要使实现同步的线程所检查的监视器对象必须是同一个对象才能够实现同步,也就是说使用同一个监视器的线程之间才能同步。
模拟死锁:
Threaddemo1.class
不变
TestThread.class
publicclassTestThreadimplementsRunnable{
inttickets=100;
Stringstr=newString("");
publicvoidrun(){
if(str.equals("System")){
while(true){
sale();
}
}else{
while(true){
synchronized(str){
if(tickets>0){
try{
Thread.sleep(10);
}catch(InterruptedExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
synchronized(this){
}
System.out.println(Thread.currentThread().getName()+"ttissalingticket"+tickets--);
}
}
}
}
}
publicsynchronizedvoidsale(){
if(tickets>0){
try{
Thread.sleep(10);
}catch(InterruptedExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
synchronized(str){}
System.out.println(Thread.currentThread().getName()+"issalingticket"+tickets--);
}
}
}
5.线程中通信
线程等待与唤醒
Producer.class
publicclassProducerimplementsRunnable{
//Producer生产者
Huangchonghc;
publicProducer(Huangchonghc){
this.hc=hc;
}
publicvoidrun(){
inti=0;
while(true){
synchronized(hc){
//要同一个对象,和Consumer里面的synchromized要一致
if(hc.bFull){
try{
hc.wait();//wait()要和监视器synchronized同一个对象
//notify(),也一样
}catch(InterruptedExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
}
if(i==0){
hc.name="张三";
try{
Thread.sleep(10);
}catch(InterruptedExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
hc.sex="男";
}else{
hc.name="李四";
try{
Thread.sleep(10);
}catch(InterruptedExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
hc.sex="女";
}
i=(i+1)%2;//百分号取余数
hc.bFull=true;
hc.notify();
}
}
}
}
Consumer.class
publicclassConsumerimplementsRunnable{
//Consumer消费者
Huangchonghc;
publicConsumer(