java中多线程总结

一.多线程实现方式——继承Thread类

  1. 线程主体
    Thread类是定义在java.lang包中,一个类只要继承Thread类,此类就称为多线程操作类,在Thread子类中,必须明确重写run()方法,此方法称为线程主体;

  2. Thread类定义
    public class Thread extends Object implements Runnable;
    从定义看,Thread类也是Runnable接口的子类。

  3. Thread总结
    启动一个线程,必须使用Thread类中定义的start()方法,一旦调用start()方法,实际上最终调用的就是run()方法。通过run()方法启动线程其实就是调用一个类中的方法,当作普通方法的方式调用,并没有创建一个新线程,程序中依旧只有一个主线程,必须等到run()方法里面的代码块执行完毕,才会继续执行下面的代码,这样就没有达到多线程的目的。

  4. 代码示例

class Thread01 extends Thread{
    private String name;
    public Thread01(String name){
        this.name = name;
    }
    public void run(){
        for(int i=0;i<10;i++){
            System.out.println(name + "运行,i=" + i);
        }
    }
}

public class Thread01_Thread{
    public static void main(String[] args) {
        Thread01 t1 = new Thread01("线程A");
        Thread01 t2 = new Thread01("线程B");
        t1.start();
        t2.start();
    }
}

二.多线程实现方式——实现Runnable接口

  1. Runnable接口的实现
    在java中也可以通过此方式实现多线程,Runnable接口中只定义了一个抽象方法run()。因此,通过Runnable接口实现多线程,只要实例化Runnable子类对象,实例化Thread对象,调用start()方法即可。

  2. Runnable接口总结
    Thread类在操作多线程的时候,无法达到资源共享的目的,因为每个对象都包含各自的属性;而使用Runnable接口可以实现资源共享。

  3. 代码示例

class Thread02 implements Runnable{
    private String name;    
    public Thread02(String name){
        this.name = name;
    }   
    @Override
    public void run() {
        for(int i=0;i<10;i++){
            System.out.println(name + "运行,i=" + i);
        }
    }   
}

public class Thread02_Runnable {
    public static void main(String[] args) {        
        Thread02 t1 = new Thread02("线程A");
        Thread02 t2 = new Thread02("线程B");      
        Thread thread1 = new Thread(t1);
        Thread thread2 = new Thread(t2);        
        thread1.start();
        thread2.start();
    }
}

三.java中启动线程start()和run()方法的区别

  1. 线程的启动
    java中启动线程有两种方法,继承Thread类和实现Runnable接口,由于java无法实现多继承,所以一般通过实现Runnable接口来创建线程。但是,不管使用哪种方法,都可以通过start()方法和run()方法来启动线程。

  2. start()方法
    通过该方法启动线程的同时也创建了一个线程,真正实现了多线程,无需等待run()方法中的代码执行完毕,就可以接着执行下面的代码。此时,start()这个线程处于就绪状态,当得到CPU的时间片后就会执行其中的run()方法。这个run()方法包含了要执行的这个线程的内容,run()方法执行完毕,此线程也就终止了。

  3. run()方法
    通过run()方法启动线程其实就是调用一个类中的方法,当作普通方法的方式调用,并没有创建一个新线程,程序中依旧只有一个主线程,必须等到run()方法里面的代码块执行完毕,才会继续执行下面的代码,这样就没有达到多线程的目的。

四.线程的强制运行

  1. join()方法
    在java多线程实现过程中,使用join()方法可以让一个线程强制运行,线程强制运行期间,其他线程无法运行,必须等此线程完成之后才可以运行。

  2. 代码示例

class Thread04 implements Runnable{
    public void run() {     
        System.out.println(Thread.currentThread().getName());       
        for(int i=0;i<50;i++){
            System.out.println(Thread.currentThread().getName() + "运行,i=" + i);
        }
    }
}

public class Thread04_join {
    public static void main(String[] args) {        
        Thread04 td = new Thread04();       
        Thread t = new Thread(td, "nice");      
        t.start();      
        for(int i=0;i<50;i++){
            if(i>10){
                try {
                    t.join();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            System.out.println("main线程运行:" + i);
        }
    }
}

五.线程的休眠

  1. sleep()方法
    在实现多线程时,在程序中允许一个线程进行短暂的休眠,直接使用Thread.sleep()方法即可。

  2. 代码示例

class Thread05 implements Runnable{
    public void run() {
        for(int i=0;i<10;i++){          
            try {
                Thread.sleep(300);
            } catch (Exception e) {
                e.printStackTrace();
            }           
            System.out.println(Thread.currentThread().getName() + "运行,i=" + i);
        }
    }
}

public class Thread05_sleep {
    public static void main(String[] args) {        
        Thread05 td = new Thread05();
        Thread t = new Thread(td, "nice");      
        t.start();
    }
}

六.后台线程

  1. 后台线程
    在java程序中,只要前台有一个程序在运行,则整个java进程就不会消失。因此,此时可以设置一个后台线程,这样即使java进程结束了,此后台线程依然可以继续执行。

  2. 代码示例

class Thread06 implements Runnable{
    public void run() {
        while(true){            
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "线程运行...");
        }
    }   
}

public class Thread06_setDeamon {
    public static void main(String[] args) {        
        Thread06 td = new Thread06();
        Thread t = new Thread(td, "nice");      
        t.start();
    }
}

七.线程的优先级

  1. setPriority()方法
    在java的线程操作中,所有的线程在运行前都会保持就绪状态,那么此时,哪个线程的优先级高,哪个线程就有可能被优先执行。

  2. 代码示例

class Thread07 implements Runnable{
    public void run() {     
        for(int i=0;i<5;i++){           
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }           
            System.out.println(Thread.currentThread().getName() + "运行,i=" +i);
        }
    }   
}

public class Thread07_priority {
    public static void main(String[] args) {        
        Thread07 td = new Thread07();
        Thread t1 = new Thread(td, "线程A");
        Thread t2 = new Thread(td, "线程B");
        Thread t3 = new Thread(td, "线程C");      
        t1.setPriority(Thread.MIN_PRIORITY);
        t2.setPriority(Thread.MAX_PRIORITY);
        t3.setPriority(Thread.NORM_PRIORITY);       
        t1.start();
        t2.start();
        t3.start();
    }
}

八.线程的同步

1)经典问题分析

  1. 经典案例:售票
    分析:票数出现负数的情况
    因为在run()方法里面加入了延迟操作,那么一个线程就有可能还没对票数进行减操作之前,其他线程就已经将票数减少了,这样一来就会出现负数情况。

  2. 死锁问题解决
    想要解决资源共享的同步操作问题,可以使用同步代码块和同步方法两种方式完成;

  3. 代码示例

class Thread08 implements Runnable{ 
    private int ticket = 5; 
    public void run() {             
        for(int i=0;i<100;i++){         
            if(ticket>0){           // 还有票              
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }               
                System.out.println(Thread.currentThread().getName() + "卖票:ticket = " + ticket--);
            }
        }
    }
}

public class Thread08_Ticket {
    public static void main(String[] args) {        
        Thread08 td = new Thread08();       
        Thread t1 = new Thread(td, "线程A");
        Thread t2 = new Thread(td, "线程B");
        Thread t3 = new Thread(td, "线程C");      
        t1.start();
        t2.start();
        t3.start();
    }
}

2)死锁问题解决——同步块

  1. 线程的同步:Synchronized
    所谓的同步,就是指多个操作在同一时间段内只能有一个线程执行,其他线程要等待此线程完成后才可以继续执行。

  2. 代码示例一同步块

class Thread04 implements Runnable{
private int ticket = 5; 
    public void run() {             
        for(int i=0;i<100;i++){         
            synchronized (this) {   // 同步代码块:对当前对象进行同步              
                if(ticket>0){       // 还有票                  
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }                   
                    System.out.println(Thread.currentThread().getName() + "卖票:ticket = " + ticket--);
                }
            }
        }
    }   
}

public class Thread04_Synchronized1 {
    public static void main(String[] args) {        
        Thread04 td = new Thread04();               
        Thread t1 = new Thread(td, "线程A");  
        Thread t2 = new Thread(td, "线程B");
        Thread t3 = new Thread(td, "线程C");      
        t1.start();     
        t2.start();
        t3.start();     
    }
}

3)死锁问题解决——同步方法

  1. 同步方法
    除了可以将需要的代码设置为同步块之外,也可以使用Synchronized关键字将一个方法设置成同步方法。
    格式:synchronized 方法返回值 方法名称(参数列表){}

  2. 代码示例

class Thread05 implements Runnable{ 
    private int ticket = 5; 
    public void run() {
        for(int i=0;i<100;i++){
            this.sale();        // 调用同步方法
        }
    }   
    public synchronized void sale(){
        if(ticket>0){
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();

            System.out.println(Thread.currentThread().getName() + "卖票:ticket = " + ticket--);
        }
    }
}

public class Thread05_Synchronized2 {
    public static void main(String[] args) {        
        Thread05 td = new Thread05();                   
        Thread t1 = new Thread(td, "线程A");      
        Thread t2 = new Thread(td, "线程B");
        Thread t3 = new Thread(td, "线程C");      
        t1.start();     
        t2.start();
        t3.start();
    }
}

九.线程的死锁

  1. 线程死锁
    当两个线程相互调用Thread.join();
    当两个线程使用嵌套的同步块时,一个线程占用了另一个线程的必需的锁,互相等待时被阻塞,就有可能出现死锁;

  2. 代码示例

class Zhangsan{ 
    public void say(){
        System.out.println("张三对李四说:“你给我画,我就把书给你。”") ;
    }
    public void get(){
        System.out.println("张三得到画了。") ;
    }
};

class Lisi{ 
    public void say(){
        System.out.println("李四对张三说:“你给我书,我就把画给你”") ;
    }
    public void get(){
        System.out.println("李四得到书了。") ;
    }
};

public class Thread06_Deadlock implements Runnable{ 
    private static Zhangsan zs = new Zhangsan() ;
    private static Lisi ls = new Lisi() ;
    private boolean flag = false ;  // 标志位,判断那个先说话  
    public void run(){              // 覆写run()方法
        if(flag){           
            synchronized(zs){       // 同步张三
                zs.say() ;
                try{
                    Thread.sleep(500) ;
                }catch(InterruptedException e){
                    e.printStackTrace() ;
                }
                // 相互等待彼此对象同步锁执行结束,相互等待引起的死锁;
                synchronized(ls){   
                    zs.get() ;
                }
            }
        }else{          
            synchronized(ls){
                ls.say() ;
                try{
                    Thread.sleep(500) ;
                }catch(InterruptedException e){
                    e.printStackTrace() ;
                }
                synchronized(zs){       
                    ls.get() ;
                }
            }
        }
    }

    public static void main(String args[]){     
        Thread06_Deadlock t1 = new Thread06_Deadlock() ;
        Thread06_Deadlock t2 = new Thread06_Deadlock() ;        
        t1.flag = true ;
        t2.flag = false ;
        Thread thA = new Thread(t1) ;
        Thread thB = new Thread(t2) ;       
        thA.start() ;
        thB.start() ;
    }
};

十.线程的生命周期

  1. 生命周期
    一个线程创建之后通过start()方法进入到运行状态,在运行状态中可以使用yield()进行礼让。但是仍然可以进行,如果现在一个线程需要暂停的话,可以使用suspend()、sleep()、wait(),如果现在线程不需要再执行,则可以通过stop()结束(如果run()方法执行完毕也表示结束),或一个新线程直接调用stop()方法也可以进行结束。

  2. 以上有如下几个方法:
    1)suspend():暂时挂机线程;
    2)resume():恢复挂起的线程;
    3)stop():停止线程;
    因为以上三个方法都会产生死锁问题,所以现在已经不建议使用了。
    现在停止线程的做法:通过设置标志位,让线程停止运行。

猜你喜欢

转载自blog.csdn.net/clearfairy/article/details/78879106