线程

1.线程的实现

  • 实现线程的第一种方式,继承thread类
class MyThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName() + "--" + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
  • 实现线程的第二种方式,实现Runnable接口
class MyRunnable implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName() + "--" + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
  • 调用线程
public static void main(String[] args) {
        MyThread mt = new MyThread();
        mt.start(); //启动线程

        //推荐
        MyRunnable mr = new MyRunnable();
        Thread t2 = new Thread(mr);
        t2.run();
    }

sleep()方法: 线程的休眠在当前线程的执行中,暂停指定的毫秒数,释放CPU的时间片,具体取决于系统定时器和调度程序的精度和准确性,线程不会丢失任何监视器的所有权


2.中断线程

实例:
我们先来创建两个线程

class MyRunnable2 implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            System.out.println(Thread.currentThread().getName() + "--" + i);
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class MyRunnable3 implements Runnable{
    public boolean flag = true;
    public MyRunnable3(){
        flag = true;
    }
    @Override
    public void run() {
        int i = 0;
        while(flag){
            System.out.println(Thread.currentThread().getName()+"---"+(i++));
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

然后调用

public static void main(String[] args) {
        MyRunnable2 run1 = new MyRunnable2();
        Thread t = new Thread(run1);
        t.start();

        MyRunnable3 rm3 = new MyRunnable3();
        Thread t3 = new Thread(rm3);
        t3.start();

        for (int i = 0; i < 50; i++) {
            System.out.println(Thread.currentThread().getName()+"<->"+i);
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (i==20){
                try {
                    t.join(); //让t线程执行完毕
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    //t3.interrupt();
                    rm3.flag = false;
                }
            }
        }
    }

表示main和t这两个线程, 先是main和t同时执行,等到main执行到i=20时,main停下,等待t执行完毕后,main再继续执行

中断方法

join方法:
加入线程,让调用的线程先执行指定时间或执行完毕
中断线程:
(1) 使用interrupt()方法来中断线程,设置一个中断状态(标记)sleep会自动清除中断标记位,
(2) 自定义标记的方式 推荐


3 守护线程与yield

public static void main(String[] args) {
        MyRunnable4 rm4 = new MyRunnable4();
        Thread t4 = new Thread(rm4);
        t4.setName("主线程"); //设置线程名称
        //设置线程优先级,优先级高可以提高线程抢占CPU时间片的概率
        t4.setPriority(Thread.MAX_PRIORITY);
        //线程可以分为守护线程和用户线程,当进程中没有用户线程时,JVM会退出
        t4.setDaemon(true); //把线程设置为守护线程
        t4.start();

        for (int i = 0; i < 20; i++) {
            System.out.println("main--"+i);
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

线程的其他方法

  • public final void setDaemon(boolean on) on=true时表示设置为守护线程
  • public final boolean isDaemon()测试这个线程是否为守护线程
  • public static void yield()暂停当前正在执行的线程对象,并执行其他线程
  • long getId() 返回该线程的标识符
  • String getName() 返回该线程的名称
  • void setName(String name) 设置该线程的名称
  • boolean isAlive()他测试线程是否处于活动状态
  • void setPriority(int newPriority) 更改线程的优先级
  • static int MAX_PRIORITY 线程可以具有的最高优先级
  • static int MIN_PRIORITY 线程可以具有的最低优先级
  • static int NORM_PRIORITY 分配给线程的默认优先级

4 线程同步

1. 多线程共享数据时,会发生线程不安全的情况
2. 多线程共享数据必须使用同步

线程同步的三种方法

1. 同步代码块

synchronized (this) {
            for (int i = 0; i < 300; i++) {
                if (ticket > 0) {
                    ticket--;
                    try {
                        Thread.sleep(1000);
                    } catch
                    (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(
                            "您购买的票已剩余:" +
                            ticket + "张");

                }
            }
        }

注意: synchronized()里面是一个同步锁,只要是一个对象就可以了

2.同步方法

public synchronized void method() {
        for (int i = 0; i < 300; i++) {
            if (ticket > 0) {
                ticket--;
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(
                        "您购买的票已剩余:" + ticket +
                                "张");

            }
        }
    }

注意: 实际上同步锁是this

3. 使用Lock(更灵活的控制)

ReentrantLock lock = new ReentrantLock();//互斥锁

    public void method2() {
        lock.lock();//锁定
        try {
            for (int i = 0; i < 300; i++) {
                if (ticket > 0) {
                    ticket--;
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(
                            "您购买的票已剩余:" + ticket + "张");
                }
            }
        } finally {
            lock.unlock(); //释放锁
        }
  }

同步准则:

    1. 使代码块保持简短,把不随线程变化的预处理和后处理移出synchronized代码块
    1. 不要阻塞,如InputStream.read().
    1. 在持有锁的时候,不要对其他对象调用同步方法

5 线程池

public static void main(String[] args) {
        //创建线程池
        //1. 创建一个单线程的线程池
        //ExecutorService es =Executors.newSingleThreadExecutor();

        //2. 创建一个固定大小的线程池
        //ExecutorService es =Executors.newFixedThreadPool(3);

        //3. 创建一个可缓存的线程池
        //ExecutorService es =Executors.newCachedThreadPool();

        //4. 创建一个大小无限的线程池
        ScheduledExecutorService sche = Executors.newScheduledThreadPool(3);
        ExecutorService es = sche;
        es.execute(new MyRunnable6());
        es.execute(new MyRunnable6());
        es.shutdown();
    }

6 生产者消费者案例

public class ThreadDemo6 {
    public static void main(String[] args) {
        Food food = new Food();
        Producter p = new Producter(food);
        Customers c = new Customers(food);
        Thread t1 = new Thread(p);
        Thread t2 = new Thread(c);
        t1.start();
        t2.start();
    }
}

/**
 * 消费者
 */
class Customers implements Runnable {
    private Food food;

    public Customers(Food food) {
        this.food = food;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            food.get();
        }
    }
}

/**
 * 生产者
 */
class Producter implements Runnable {
    private Food food;

    public Producter(Food food) {
        this.food = food;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            if (i % 2 == 0) {
                food.set("锅包肉", "酸甜口味");
            } else {
                food.set("佛跳墙", "美容养颜");
            }
        }
    }
}


class Food {
    private String name;
    private String desc;
    private boolean flag = true;  //true表示可以生产,
    // false表示可以消费

    /**
     * 生产产品
     */
    public synchronized void set(String name,
                                 String desc) {
        //不能生产
        if (!flag) {
            try {
                this.wait(); //线程进入等待状态,
                // 释放监视器所有权(对象锁)
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
        if (flag) {
            this.setName(name);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            this.setDesc(desc);
            flag = false;
            this.notify(); //唤醒等待的线程(随机的其中一个)
        }

    }

    /**
     * 消费产品
     */
    public synchronized void get() {
        //不能消费
        if (flag) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        if (!flag) {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(this.getName() + "--" + this.getDesc());
            flag = true;
            this.notifyAll();
        }
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    @Override
    public String toString() {
        return "Food{" +
                "name='" + name + '\'' +
                ", desc='" + desc + '\'' +
                '}';
    }

    public Food(String name, String desc) {
        this.name = name;
        this.desc = desc;
    }

    public Food() {
        super();
    }
}
  • 两个线程协同工作: 先生产,再消费
  • wait()里面如果加入时间,则能自动唤醒
  • 面试题: sleep和 wait的 区别?
  • sleep:让线程进入休眠状态,让出CPU的时间片,不释放对象监视器的所有权
  • wait: 让线程进入等待状态,让出CPU的时间片,并释放对象监视器的所有权,
  • 等待其他线程通过notify()方法来唤醒


    java-thread.jpg

你可能感兴趣的:(线程)