线程&并发基础

  按照万物皆对象的思想,Java实现创建线程肯定是通过某个类或者某个借口来实现的,也就是说某个类或接口的一个实例就是一个线程。Java中便提供了Runable类和Thread类来帮我们创建线程。

继承Thread类创建线程

  若某个类想让它的实例称为一个线程,继承Thread类,再覆盖run()方法即可。

  • 创建类
public class ExtThread extends Thread{
    public void run() {
        for(int i = 0; i < 100; i++) {
            System.out.println(this.getName() +"  " + i);
        }
    }
}
  • 创建线程
public static void main(String[] args) {
    Thread et1 = new ExtThread();
    Thread et2 = new ExtThread();
    et1.start();
    et2.start();
}

实现Runnable接口创建线程

  创建一个类实现Runnable接口,实现的run()方法就是线程中真正执行的方法。

  • 创建类
public class ImpRunnable implements Runnable {
    public void run() {
        for(int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + "    "+i);
        }
    }
}
  • 创建线程
public static void main(String[] args) {
    ImpRunnable ir = new ImpRunnable();
    Thread t1 = new Thread(ir);
    Thread t2 = new Thread(ir);
    t1.start();
    t2.start();
}

Thread&Runnable

  JDK第一句对Runnable的解释是:The Runnable interface should be implemented by any class whose instances are intended to be executed by a thread. 所以任何可以创建线程的类都实现了Runnable 接口,Thread也不例外:JDK中:public class Thread implements Runnable { ... }。所以对线程进行操纵的类是Thread类,起核心功能的是Runnable中的run()方法。
  在实际使用时多使用实现Runnable接口创建线程这种方式。因为Java只支持单一继承,继承Thread类之后不方便拓展其他功能。

synchronized

  经典案例,买票问题。

  • 卖票类
public class Ticket implements Runnable{
    private int tickets = 100;
    public void run() {
        while(true) {
            if(tickets > 0) {
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("正在卖第" + tickets-- + "张票");
            }else
                System.exit(0);
        }
    }
}
  • 三个卖票窗口卖票
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.start();
    t2.start();
    t3.start();
}

  执行后的结果发现有的票被卖了两次,还卖了不存在的票。

异常

  解决方案,使用同步代码块。

public class Ticket implements Runnable{
    private int tickets = 100;
    Object o = new Object();
    public void run() {
        synchronized (o) {
            while(true) {
                if(tickets > 0) {
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("正在卖第" + tickets-- + "张票");
                }else
                    System.exit(0);
            }
        }
    }
}

  当然还可以使用同步方法。

public class Ticket implements Runnable{
    private int tickets = 100;
    Object o = new Object();
    public void run() {
        extracted();
    }
    private synchronized void extracted() {
        while(true) {
            if(tickets > 0) {
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("正在卖第" + tickets-- + "张票");
            }else
                System.exit(0);
        }
    }
}

  这个时候锁的是当前对象this。如果方法是static的,锁此类的字节码对象。

你可能感兴趣的:(线程&并发基础)