java复习手册:多线程编程

进程与线程

多线程开发的本质是实质上是多个线程对同一类资源进行抢占。

Thread类实现多线程

package ali;

public class Demo01 {
    public static void main(String[] args) {
        new MyThread("小明").start();
        new MyThread("小红").start();
    }
}
class MyThread extends Thread{
    private String title;
    public MyThread(String title) {
        this.title = title;
    }
    public void run() {
        for(int i=0;i<10;++i) {
            System.out.println(this.title + " " + i);
        }
    }
}

Runnable接口实现多线程

package ali;

public class Demo02 {
    public static void main(String[] args) {
        new Thread(new MyThread("票贩子A")).start();
        new Thread(new MyThread("票贩子B")).start();
        new Thread(new MyThread("票贩子C")).start();
    }
}
class MyThread02 implements Runnable{
    private String title;
    public MyThread02(String title) {
        this.title = title;
    }
    public void run() {
        for(int i=0;i<10;++i) {
            System.out.println(this.title + " " + i);
        }
    }
}
public class Demo01 {
    public static void main(String[] args) {
        new MyThread("小明").start();
        new MyThread("小红").start();
    }
}
class MyThread extends Thread{
    private String title;
    public MyThread(String title) {
        this.title = title;
    }
    public void run() {
        for(int i=0;i<10;++i) {
            System.out.println(this.title + " " + i);
        }
    }
}

JNI技术

JNI是Java Native Interface的缩写,通过使用 Java本地接口书写程序,可以确保代码在不同的平台上方便移植。 [1]  从Java1.1开始,JNI标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI一开始是为了本地已编译语言,尤其是C和C++而设计的,但是它并不妨碍你使用其他编程语言,只要调用约定受支持就可以了。使用java与本地已编译的代码交互,通常会丧失平台可移植性。但是,有些情况下这样做是可以接受的,甚至是必须的。例如,使用一些旧的库,与硬件、操作系统进行交互,或者为了提高程序的性能。JNI标准至少要保证本地代码能工作在任何Java 虚拟机环境。

Thread 和 Runnable的关系

Thread 类的定义

  public class Thread extends Object implements Runnable{
  }

1567412684825

在使用Thread类启动多线程的时候,调用的是start()方法,而后找到的是run()方法,但通过Thread类的构造方法传递了一个Runnable接口对象的时候,那么该接口被Thread类中的target属性保存,在start()方法执行的时候,会调用Thread类中的run()方法,而这个run()方法去调用Runnable接口子类覆写过的run()方法。

Thread类主要描述的是线程,而Runnable主要描述的是资源

用一个买票程序来实现多个线程对同一资源的并发访问。

1567415753032

package ali;

public class Demo03 {
    public static void main(String[] args) {
        MyThread03 mt = new MyThread03();
        new Thread(mt).start();
        new Thread(mt).start();
        new Thread(mt).start();
    }
}
class MyThread03 implements Runnable{
    private String title;
    private int tickets = 10;
    public void run() {
        while(tickets>0) {
            System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets-- + "张票");
        }
    }
}

1567415919629

Callable接口实现多线程

Runnable接口实现多线程有一个缺点,当线程执行完毕之后,无法获得一个返回值。在jdk1.5之后,提出了一个新的线程实现接口: java.util.concurrent.Callable

接口的定义:

public interface Callable<V>{
    public V call() throws Exception{    
    }
}

可以设置一个泛型,泛型的类型就是返回数据的类型,这样的好处是可以避免向下转型带来的隐患问题。

线程运行状态

1567417784993

线程的命名和取得

package ali;

class MyThread05 implements Runnable{
    public void run(){
        System.out.println(Thread.currentThread().getName());
    }
}
public class Demo05 {
    public static void main(String[] args) {
        MyThread05 mt = new MyThread05();
        new Thread(mt,"A").start();
        new Thread(mt).start();
        new Thread(mt,"C").start();
        mt.run();
        //main
    }
}

主线程负责整体运行,子线程负责耗时操作:

package ali;

public class Demo100 {


    public static void main(String[] args) {
    
        System.out.println("执行操作任务一");
//        int temp = 0;
//        for(int i=0;i<Integer.MAX_VALUE;++i) {
//            temp+=i;
//        }    
        new Thread(()->{
            int temp1 = 0;
            for(int i=0;i<Integer.MAX_VALUE;++i) {
                temp1+=i;
            }            
        }).start();    
        System.out.println("执行操作任务二");
        System.out.println("执行操作任务三");
    }
}

线程的休眠

如果希望某个线程可以暂缓一会的时候,可以进行休眠操作

1567420957933

在进行线程休眠的时候可能会造成中断异常

1567421077303

package ali;

public class Demo06 {
    public static void main(String[] args) {
        for(int i=0;i<5;++i) {
            new Thread(()->{
                for(int j=0;j<10;++j) {
                    System.out.println(Thread.currentThread().getName()+ " j = "+ j);
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }).start();; 
        }
    }
}

1567431333696

线程中断

线程休眠的时候是会被其他线程打断的。

在Thread类里提供两种中断执行的处理方法:

1.判断线程是否被中断:

public  boolean isInterrupted();

2.中断线程执行:

public void interrupt();
package ali;

public class Demo07 {
    public static void main(String[] args) throws InterruptedException {
        Thread td = new Thread(()->{
            System.out.println("我需要休息十秒");
            try {
                Thread.sleep(10000);
                System.out.println("我睡够了");
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                //e.printStackTrace();
                System.out.println("我被吵起来了");
            }
        });
        td.start();
        Thread.sleep(1000);
        if(!td.isInterrupted()) {
            //
            System.out.println("闹钟响了");
            td.interrupt();
        }
    }
}

线程强制运行

线程的强制运行是指,当线程满足某些条件之后,某一个线程对象可以一直独占资源,直到该线程的程序执行结束。

public final void join() throws InterruptedException
package ali;

public class Demo08 {
    public static void main(String[] args) {
        Thread mainThread = Thread.currentThread();
        Thread td = new Thread( ()->{
            for(int i=0;i<100;++i) {
                if(i==3) {
                    try {
                        mainThread.join();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + " 执行i= " + i);
            }
        },"玩耍的线程" ); 
        td.start();
        
        for(int i=0;i<100;++i) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println("霸道的主线程"+" 执行i=" + i);
        }
    }
}

线程的礼让

线程的礼让是指线程先将资源让出去让别的线程执行。

定义为:

public final void yield()
package ali;

public class Demo08 {
    public static void main(String[] args) {
        Thread mainThread = Thread.currentThread();
        Thread td = new Thread( ()->{
            for(int i=0;i<100;++i) {
                if(i % 10 == 0) {
                    Thread.yield();
                    System.out.println("               玩耍的线程礼让执行");
                }
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + " 执行i= " + i);
            }
        },"玩耍的线程" ); 
        td.start();
        
        for(int i=0;i<100;++i) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println("霸道的主线程"+" 执行i=" + i);
        }
    }
}

礼让执行的时候每一次调用yiled()方法,都只会礼让一次当前的资源

线程的优先级

从理论上来讲线程的优先级越高越有可能执行(越有可能抢占到资源)。

设置优先级:

public final void setPriority(int newPriority )

获取优先级:

public final int setPriority()

1567434756477

package ali;

public class Demo09 {
    //private static final int MAX_PRIORITY = 0;

    public static void main(String[] args) {
        Thread t1 = new Thread( new MyThread09(),"小快" );
        Thread t2 = new Thread( new MyThread09(),"小慢" );
        t1.setPriority(    Thread.MAX_PRIORITY);
        t2.setPriority( Thread.MIN_PRIORITY);
        t1.start();
        t2.start();
    }
}
class MyThread09 implements Runnable{
    public void run() {
        for(int i=0;i<100;++i) {
            System.out.println(Thread.currentThread().getName() + i);
        }
    }
}

同步问题引出

package ali;

public class Demo10 {
    public static void main(String[] args) {
        MyThread10 m1 = new MyThread10();
        new Thread(m1,"票贩子A").start();
        new Thread(m1,"票贩子B").start();
        new Thread(m1,"票贩子C").start();
    }
}

class MyThread10 implements Runnable{
    private int tickets = 10;
    public void run() {
        while(true) {
            if(tickets>0) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "正在出售第 " + tickets-- + "张票 ");
            }else {
                break;
            }
        }
    }
}

线程同步处理

同步问题的解决在于锁,指的是当某一个线程执行操作的时候,其他线程外面等待。

1567436395547

用synchronized 关键字来实现。

synchronized(同步对象){
    同步代码块
}
package ali;

public class Demo11 {
    public static void main(String[] args) {
        MyThread11 m1 = new MyThread11();
        new Thread(m1,"票贩子A").start();
        new Thread(m1,"票贩子B").start();
        new Thread(m1,"票贩子C").start();
    }
}

class MyThread11 implements Runnable{
    private int tickets = 10;
    public void run() {
        while(true) {
            synchronized(this) {
                if(this.tickets>0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "正在出售第 " + tickets-- + "张票 ");
                }else {
                    break;
                }                
            }
        }
    }
}

加入同步之后,性能降低了。

可以同步方法,在方法 的定义上使用synchronized。

package ali;

public class Demo10 {
    public static void main(String[] args) {
        MyThread10 m1 = new MyThread10();
        new Thread(m1,"票贩子A").start();
        new Thread(m1,"票贩子B").start();
        new Thread(m1,"票贩子C").start();
    }
}

class MyThread10 implements Runnable{
    private int tickets = 10;
    public void run() {
        while(true) {
            if(tickets>0) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "正在出售第 " + tickets-- + "张票 ");
            }else {
                break;
            }
        }
    }
}
Last modification:December 21st, 2019 at 05:03 am
如果觉得我的文章对你有用,请随意赞赏