其他分享
首页 > 其他分享> > day11 - 多线程

day11 - 多线程

作者:互联网

1内容

          线程等待唤醒机制

进程(Process)

多线程的意义:

随着处理器上的核心数量越来越多,现在大多数计算机都比以往更加擅长并行计算

而一个线程,在一个时刻,只能运行在一个处理器核心上

试想一下,一个单线程程序,在运行时只能使用一个处理器核心,那么再多的处理器核心加入也无法显著提升该程序的执行效率。

 

相反,如果该程序使用多线程技术,将计算逻辑分配到多个处理器核心上,就会显著减少程序的处理时间,并且随着更多处理器核心的加入而变得更有效率。

总结:使用多线程可以提高程序的执行效率

2、Java 中线程的实现方式

1.继承 Thread 类

方法名说明
void run() 在线程开启后,此方法将被调用执行
void start() 使此线程开始执行,Java虚拟机会调用run方法()

 

 

 

 

实现步骤

public class MyThread extends Thread {
    @Override
    public void run() {
        for(int i=0; i<100; i++) {
            System.out.println(i);
        }
    }
}
public class MyThreadDemo {
    public static void main(String[] args) {
        MyThread my1 = new MyThread();
        MyThread my2 = new MyThread();

        // my1.run();
        // my2.run();

        // void start() 导致此线程开始执行; Java虚拟机调用此线程的run方法
        my1.start();
        my2.start();
    }
}

 

两个小问题

run() 方法 和 start() 方法的区别?

run():封装线程执行的代码,直接调用,相当于普通方法的调用

  1. start():启动线程;然后由JVM调用此线程的run()方法

2.实现 Runable 接口

 

public class MyRunnable implements Runnable {
    @Override
    public void run() {
        for(int i=0; i<100; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}
public class MyRunnableDemo {
    public static void main(String[] args) {
        // 创建MyRunnable类的对象
        MyRunnable my = new MyRunnable();

        // 创建Thread类的对象,把MyRunnable对象作为构造方法的参数
        // Thread(Runnable target)
        // Thread t1 = new Thread(my);
        // Thread t2 = new Thread(my);
        // Thread(Runnable target, String name)
        Thread t1 = new Thread(my,"坦克");
        Thread t2 = new Thread(my,"飞机");

        // 启动线程
        t1.start();
        t2.start();
    }
}

3.实现 Callable 接口

 

public class MyCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        for (int i = 0; i < 100; i++) {
            System.out.println("跟女孩表白" + i);
        }
        // 返回值就表示线程运行完毕之后的结果
        return "答应";
    }
}
public class Demo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 线程开启之后需要执行里面的call方法
        MyCallable mc = new MyCallable();

        // Thread t1 = new Thread(mc);

        // 可以获取线程执行完毕之后的结果.也可以作为参数传递给Thread对象
        FutureTask<String> ft = new FutureTask<>(mc);

        // 创建线程对象
        Thread t1 = new Thread(ft);

        // String s = ft.get();
        // 开启线程
        t1.start();

        String s = ft.get();
        System.out.println(s);
    }
}

三种实现方式的对比

 

3、线程中的相关方法

 

设置和获取线程名称

方法名说明
void setName(String name) 将此线程的名称更改为等于参数name
String getName() 返回此线程的名称
Thread currentThread() 返回对当前正在执行的线程对象的引用
public class MyThread extends Thread {
    public MyThread() {}
    public MyThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(getName()+":"+i);
        }
    }
}
public class MyThreadDemo {
    public static void main(String[] args) {
        MyThread my1 = new MyThread();
        MyThread my2 = new MyThread();

        // void setName(String name):将此线程的名称更改为等于参数 name
        my1.setName("高铁");
        my2.setName("飞机");

        // Thread(String name)
        MyThread my1 = new MyThread("高铁");
        MyThread my2 = new MyThread("飞机");

        my1.start();
        my2.start();

        // static Thread currentThread() 返回对当前正在执行的线程对象的引用
        System.out.println(Thread.currentThread().getName());
    }
}

 

线程休眠

方法名说明
static void sleep(long millis) 使当前正在执行的线程停留(暂停执行)指定的毫秒数
 1 public class MyRunnable implements Runnable {
 2     @Override
 3     public void run() {
 4         for (int i = 0; i < 100; i++) {
 5             try {
 6                 Thread.sleep(100);
 7             } catch (InterruptedException e) {
 8                 e.printStackTrace();
 9             }
10 
11             System.out.println(Thread.currentThread().getName() + "---" + i);
12         }
13     }
14 }
15 public class Demo {
16     public static void main(String[] args) throws InterruptedException {
17         /*
18             System.out.println("睡觉前");
19             Thread.sleep(3000);
20             System.out.println("睡醒了");
21         */
22 
23         MyRunnable mr = new MyRunnable();
24 
25         Thread t1 = new Thread(mr);
26         Thread t2 = new Thread(mr);
27 
28         t1.start();
29         t2.start();
30     }
31 }

线程优先级

优先级相关方法

方法名说明
final int getPriority() 返回此线程的优先级
final void setPriority(int newPriority) 更改此线程的优先级线程默认优先级是5;线程优先级的范围是:1-10

代码演示

public class MyCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + "---" + i);
        }
        return "线程执行完毕了";
    }
}
public class Demo {
    public static void main(String[] args) {
        // 优先级: 1 - 10 默认值:5
        MyCallable mc = new MyCallable();

        FutureTask<String> ft = new FutureTask<>(mc);

        Thread t1 = new Thread(ft);
        t1.setName("飞机");
        t1.setPriority(10);
        // System.out.println(t1.getPriority());//5
        t1.start();

        MyCallable mc2 = new MyCallable();

        FutureTask<String> ft2 = new FutureTask<>(mc2);

        Thread t2 = new Thread(ft2);
        t2.setName("坦克");
        t2.setPriority(1);
        // System.out.println(t2.getPriority());//5
        t2.start();
    }
}

 

4、线程同步

卖票案例

 1 public class SellTicket implements Runnable {
 2     private int tickets = 100;
 3     // 在SellTicket类中重写run()方法实现卖票,代码步骤如下
 4     @Override
 5     public void run() {
 6         while (true) {
 7             if(ticket <= 0){
 8                     // 卖完了
 9                     break;
10                 }else{
11                     try {
12                         Thread.sleep(100);
13                     } catch (InterruptedException e) {
14                         e.printStackTrace();
15                     }
16                     ticket--;
17                     System.out.println(Thread.currentThread().getName()
18                                                        + "在卖票,还剩下" + ticket + "张票");
19                 }
20         }
21     }
22 }
23 public class SellTicketDemo {
24     public static void main(String[] args) {
25         // 创建SellTicket类的对象
26         SellTicket st = new SellTicket();
27 
28         // 创建三个Thread类的对象,把SellTicket对象作为构造方法的参数,并给出对应的窗口名称
29         Thread t1 = new Thread(st,"窗口1");
30         Thread t2 = new Thread(st,"窗口2");
31         Thread t3 = new Thread(st,"窗口3");
32 
33         // 启动线程
34         t1.start();
35         t2.start();
36         t3.start();
37     }
38 }

Lock锁

虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁,为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock

Lock是接口不能直接实例化,这里采用它的实现类ReentrantLock来实例化

public class Ticket implements Runnable {
    //票的数量
    private int ticket = 100;
    private Object obj = new Object();
    private ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        while (true) {
            //synchronized (obj){//多个线程必须使用同一把锁.
            try {
                lock.lock();
                if (ticket <= 0) {
                    //卖完了
                    break;
                } else {
                    Thread.sleep(100);
                    ticket--;
                    System.out.println(Thread.currentThread().getName() 
                                                           + "在卖票,还剩下" + ticket + "张票");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }
}

public class Demo {
    public static void main(String[] args) {
        Ticket ticket = new Ticket();

        Thread t1 = new Thread(ticket);
        Thread t2 = new Thread(ticket);
        Thread t3 = new Thread(ticket);

        t1.setName("窗口一");
        t2.setName("窗口二");
        t3.setName("窗口三");

        t1.start();
        t2.start();
        t3.start();
    }
}

死锁

 1 public class Demo {
 2     public static void main(String[] args) {
 3         Object objA = new Object();
 4         Object objB = new Object();
 5 
 6         new Thread(()->{
 7             while(true){
 8                 synchronized (objA){
 9                     // 线程一
10                     System.out.println(Thread.currentThread().getName() + "----抢到了执行权, 上A锁");
11                     synchronized (objB){
12                         System.out.println(Thread.currentThread().getName() + "----抢到了执行权, 上B锁");
13                     }
14                 }
15             }
16         }).start();
17 
18         new Thread(()->{
19             while(true){
20                 synchronized (objB){
21                     // 线程二
22                     System.out.println(Thread.currentThread().getName() + "----抢到了执行权, 上B锁");
23                     synchronized (objA){
24                         System.out.println(Thread.currentThread().getName() + "----抢到了执行权, 上A锁");
25                     }
26                 }
27             }
28         }).start();
29     }
30 }

5、线程等待唤醒机制

 

生产者和消费者模式概述

 

生产者和消费者案例

 

public class Box {
    public static boolean flag = false;
}


public class Consumer extends Thread {
    @Override
    public void run() {
        while (true) {
            synchronized (Box.class) {
                if (Box.flag == false) {
                    // 等待
                    try {
                        System.out.println("没有包子了, 消费者等待...");
                        Box.class.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    System.out.println("消费者开吃....");
                    Box.flag = false;
                    Box.class.notifyAll();
                }
            }
        }
    }
}

public class Maker extends Thread{
    @Override
    public void run() {
        while(true){
            synchronized (Box.class) {
                if(Box.flag == false){
                    // 没包子了, 生产者制作
                    System.out.println("生产制作包子....");
                    Box.flag = true;
                    Box.class.notifyAll();
                }else {
                    // 有包子, 生产者等待
                    System.out.println("有包子, 生产者等待");
                    try {
                        Box.class.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

public class Test {
    public static void main(String[] args) {
        Consumer c = new Consumer();
        Maker m = new Maker();

        c.start();
        m.start();
    }
}

如有问题,请邮件联系!!!!

标签:Thread,void,class,线程,day11,new,多线程,public
来源: https://www.cnblogs.com/sunyanh/p/16459492.html