Java_多线程

线程要依附进程存在

多线程的实现一定要有一个线程的主类,而主类往往需要操作一些资源,但对于多线程主类的实现有一定的要求:

1. 继承Thread父类;

2. 实现Runnable接口(Callable接口)

继承Thread类实现多线程:

在java.lang包有Thread类,子类继承Thread后要覆写Thread类中的run()方法,这个方法就属于线程的主方法。

 定义:public void run();

范例:线程的主体类;

class MyThread extends Thread{ //表示实现多线程
    private String name;
    public MyThread(String name) { //线程的名字
        this.name = name;
    }
    @Override
    public void run() { //覆写run()方法,线程的主方法
        for(int x = 0; x < 10; x++) {
            System.out.println(this.name + ", x = " + x);
        }
    }
}

上面是将内容输出10次,所有的线程并发执行,即在一个时间段上会有多个线程交替执行,所以不能直接调用run方法,而应该调用Thread类中的start()方法启动多线程。

public void start()

范例:启动多线程 

class MyThread extends Thread{ //表示实现多线程
    private String name;
    public MyThread(String name) { //线程的名字
        this.name = name;
    }
    @Override
    public void run() { //覆写run()方法,线程的主方法
        for(int x = 0; x < 10; x++) {
            System.out.println(this.name + ", x = " + x);
        }
    }
}
public class Hello{
    public static void main(String[] args) {
        MyThread mt1 = new MyThread("线程A");
        MyThread mt2 = new MyThread("线程B");
        MyThread mt3 = new MyThread("线程C");
        mt1.start();
        mt2.start();
        mt3.start();
    }    
}

结果混乱,是因为交替执行,没有固定的执行顺序。若不调用start而调用run,就是顺序执行 

实现Runnable接口

继承Thread会有单继承的局限,所以最好的做法是利用接口来解决,于是使用Runnable接口。

public interface Runnable {
    public void run();    
}

按照正常思路实现Runnable多线程:

class MyThread implements Runnable{ //表示实现多线程
    private String name;
    public MyThread(String name) { //线程的名字
        this.name = name;
    }
    @Override
    public void run() { //覆写run()方法,线程的主方法
        for(int x = 0; x < 10; x++) {
            System.out.println(this.name + ", x = " + x);
        }
    }
}

此时如果想开始多线程,由于现在实现的是Runnable接口,所以无法用Thread类中的start方法了,现在使用匿名内部类来使用start方法

class MyThread implements Runnable{ //表示实现多线程
    private String name;
    public MyThread(String name) { //线程的名字
        this.name = name;
    }
    @Override
    public void run() { //覆写run()方法,线程的主方法
        for(int x = 0; x < 10; x++) {
            System.out.println(this.name + ", x = " + x);
        }
    }
}
public class Hello{
    public static void main(String[] args) {
        MyThread mt1 = new MyThread("线程A");
        MyThread mt2 = new MyThread("线程B");
        MyThread mt3 = new MyThread("线程C");
        new Thread(mt1).start();  //匿名
        new Thread(mt2).start();
        new Thread(mt3).start();
    }    
}

面试题

继承Thread类和Runnable接口两种实现方式的区别:

  多线程一定需要一个线程的主类,要么继承Thread类,要么实现Runnable接口

  使用Runnable接口可以比Thread更好实现数据共享操作,利用Runnable接口可以避免单继承局限问题

  

Thread类实现了Runnable接口。

Runnable接口实现的多线程要比Thread类实现的多线程更方便的表现出数据共享的概念

范例:希望有三个线程进行买票 - Thread实现会发现三个线程各自卖各自的票,票没有了其他线程也不知道

class MyThread extends Thread{ //表示实现多线程
    private int ticket = 5;
    
    @Override
    public void run() { //覆写run()方法,线程的主方法
        for(int x = 0; x < 50; x++) {
            if(this.ticket>0) {
                System.out.println("卖票,ticket = " + this.ticket --);
            }
        }
    }
}
public class Hello{
    public static void main(String[] args) {
        MyThread mt1 = new MyThread();
        MyThread mt2 = new MyThread();
        MyThread mt3 = new MyThread();
        mt1.start();
        mt2.start();
        mt3.start();
    }    
}

使用Runnable接口实现:

class MyThread implements Runnable{ //表示实现多线程
    private int ticket = 5;
    
    @Override
    public void run() { //覆写run()方法,线程的主方法
        for(int x = 0; x < 50; x++) {
            if(this.ticket>0) {
                System.out.println("卖票,ticket = " + this.ticket --);
            }
        }
    }
}
public class Hello{
    public static void main(String[] args) {
        MyThread mt = new MyThread();
        new Thread(mt).start();
        new Thread(mt).start();
        new Thread(mt).start();
    }    
}

Callable接口:

比Runnable的好处是可以返回值

class MyThread implements Callable<String>{ //表示实现多线程
    private int ticket = 5;
    
    @Override
    public String call() { //覆写run()方法,线程的主方法
        for(int x = 0; x < 50; x++) {
            if(this.ticket>0) {
                System.out.println("卖票,ticket = " + this.ticket --);
            }
        }
        return "票卖完了";
    }
}
public class Hello{
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        Callable<String> cal = new MyThread();
        FutureTask<String> task = new FutureTask<>(cal);
        Thread thread = new Thread(task);
        thread.start();
        System.out.println(task.get()); //取得线程主方法的返回值
    }    
}

线程休眠

可以让某些线程延缓执行

休眠方法:public static void sleep (long millis) throws InterruptedException;

如果休眠时间没到就停止休眠了,那么就会产生中断异常。

Thread.sleep(1000);  加上这一句,延迟一秒,会有报错,点报错纠错就对了

class MyThread implements Runnable{ //表示实现多线程    
    @Override
    public void run() { //覆写run()方法,线程的主方法
        for(int x = 0; x < 100; x++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }  //休眠一秒
            System.out.println(Thread.currentThread().getName() + ", x = " + x);
        }
    }
}
public class Hello{
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        MyThread mt = new MyThread();
        new Thread(mt, "线程A").start();
        new Thread(mt, "线程B").start();
        new Thread(mt, "线程C").start();
    }    
}

线程的优先级

优先级越高的线程越有可能先执行,而在Thread类定义一下优先级方法

  设置优先级:public final void setPriority(int newPriority);

  取得优先级:public final int getPriority();

优先级定义有三种:

最高优先级:public static final int MAX_PRIORITY,10;

中等优先级:public static final int NORM_PRIORITY,5;

最低优先级:public static final int MIN_PRIORITY,1;

class MyThread implements Runnable{ 
    @Override
    public void run() { 
        for(int x = 0; x < 100; x++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }  
            System.out.println(Thread.currentThread().getName() + ", x = " + x);
        }
    }
}
public class Hello{
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        MyThread mt = new MyThread();
        Thread t1 = new Thread(mt, "线程A");
        Thread t2 = new Thread(mt, "线程B");
        Thread t3 = new Thread(mt, "线程C");
        t1.setPriority(Thread.MAX_PRIORITY);
        t2.setPriority(Thread.MIN_PRIORITY);
        t3.setPriority(Thread.MIN_PRIORITY);
        t1.start();
        t2.start();
        t3.start();
    }    
}

设置优先级只是理论上的,不一定真的就是优先

范例:主线程的优先级是什么

public class Hello{
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        System.out.println(Thread.currentThread().getPriority());
    }    
}

结果是5,主线程属于中等优先级

总结:

线程要有名字,Thread.currentThread取得当前线程;

线程的休眠有先后顺序

优先级越高理论上越有可能先执行

线程同步,多线程需要访问同一资源

同步代码块:使用synchronized关键字定义的代码块就是同步代码块,但同步的时候需要设置一个同步对象,往往使用this同步当前对象。

范例:买票,买票最后票的数量不能出现负数

class MyThread implements Runnable{
    private int ticket = 50;
    @Override
    public void run() {
        for(int x = 0; x < 100; x ++) {
            synchronized (this) { //同步代码块
                if(this.ticket > 0) {
                    try {
                        Thread.sleep(100); //延迟一秒
                    }
                    catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ", ticket = " + this.ticket --);
                }
            }
        }
    }
}


public class Hello{
    public static void main(String[] args) throws Exception {
        MyThread mt = new MyThread();
        Thread t1 = new Thread(mt,"票贩子A");
        Thread t2 = new Thread(mt,"票贩子B");
        Thread t3 = new Thread(mt,"票贩子C");
        t1.start();
        t2.start();
        t3.start();
    }
}

 另一种实现方式,synchronized方法

class MyThread implements Runnable{
    private int ticket = 5;
    @Override
    public void run() {
        for(int x = 0; x < 10; x ++) {
            this.sale();
            }
        }
    
    public synchronized void sale() { //卖票
        if(this.ticket > 0) {
            try {
                Thread.sleep(100); //延迟一秒
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ", ticket = " + this.ticket --);
        }
    }
}


public class Hello{
    public static void main(String[] args) throws Exception {
        MyThread mt = new MyThread();
        Thread t1 = new Thread(mt,"票贩子A");
        Thread t2 = new Thread(mt,"票贩子B");
        Thread t3 = new Thread(mt,"票贩子C");
        t1.start();
        t2.start();
        t3.start();
    }
}
原文地址:https://www.cnblogs.com/lonske/p/8798235.html